Django: Perché alcuni campi modello si scontrano tra loro?


174

Voglio creare un oggetto che contiene 2 collegamenti agli utenti. Per esempio:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

ma visualizzo i seguenti errori durante l'esecuzione del server:

  • Accessor per il campo "target" si scontra con il campo correlato "User.gameclaim_set". Aggiungi un argomento related_name alla definizione di 'target'.

  • L'accessorio per il campo "richiedente" si scontra con il campo correlato "User.gameclaim_set". Aggiungi un argomento related_name alla definizione di 'claimer'.

Puoi spiegare perché sto ricevendo gli errori e come risolverli?


Questi messaggi di errore sono davvero buoni. Spiegano già come risolverli. E leggere su ** [ related_namenella documentazione] ** ( docs.djangoproject.com/en/dev/ref/models/fields/#arguments ) spiegherà perché si verificano.
Lutz Prechelt,

Risposte:


294

Hai due chiavi esterne per l'utente. Django crea automaticamente una relazione inversa tra l'utente e GameClaim, che di solito è gameclaim_set. Tuttavia, poiché hai due FK, avresti due gameclaim_setattributi, il che è ovviamente impossibile. Quindi devi dire a Django quale nome usare per la relazione inversa.

Utilizzare l' related_nameattributo nella definizione FK. per esempio

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

49
Buona risposta, ma non credo che tu abbia avuto successo nell'evitare la maleducazione: P Il "perché" non è ovvio se non sei consapevole di come il django funzioni internamente.
Kenny,

14
Per qualcuno che sta imparando il framework, questo non sarebbe ovvio.
jkyle,

3
Grazie, il messaggio di errore non era nemmeno ovvio per me, ma la tua spiegazione sulla relazione inversa è stata molto utile.
ruquay,

1
Solo perché i Clash erano una buona band, non li rende un messaggio di errore particolarmente descrittivo;)
btown

7
Va anche detto che se non è necessario utilizzare le relazioni inverse per tutti i modelli. In alcuni casi potresti desiderare che la relazione modello sia unidirezionale. In questo caso si utilizza related_name = '+'. Questo dice a Django di creare una relazione unidirezionale e ignorare la relazione inversa.
Tommy Strand,

8

Il Usermodello sta cercando di creare due campi con lo stesso nome, uno per quello GameClaimsche ha quello Usercome target, e un altro per quello GameClaimsche ha quelloUser come claimer. Ecco i documentirelated_name , che è il modo in cui Django ti consente di impostare i nomi degli attributi in modo che quelli generati automaticamente non siano in conflitto.


7

L'OP non utilizza una classe base astratta ... ma se lo sei, scoprirai che la codifica rigida di related_name nell'FK (es. ..., related_name = "myname") comporterà una serie di questi errori di conflitto - uno per ogni classe ereditata dalla classe base. Il link fornito di seguito contiene la soluzione alternativa, che è semplice, ma sicuramente non ovvia.

Dai documenti di django ...

Se si utilizza l'attributo related_name su ForeignKey o ManyToManyField, è necessario specificare sempre un nome inverso univoco per il campo. Ciò causerebbe normalmente un problema nelle classi di base astratte, poiché i campi di questa classe sono inclusi in ciascuna delle classi figlio, con gli stessi valori per gli attributi (incluso related_name) ogni volta.

Maggiori informazioni qui .


2

A volte è necessario utilizzare una formattazione aggiuntiva, in related_name realtà, ogni volta che viene utilizzata l'ereditarietà.

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

Nessun scontro qui, ma related_name viene definito una volta e Django si occuperà della creazione di nomi di relazioni univoci.

quindi nei figli della classe Value, avrai accesso a:

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

0

Mi sembra di imbattermi di tanto in tanto quando aggiungo un sottomodulo come applicazione a un progetto django, ad esempio vista la seguente struttura:

myapp/
myapp/module/
myapp/module/models.py

Se aggiungo quanto segue a INSTALLED_APPS:

'myapp',
'myapp.module',

Django sembra elaborare due volte il file myapp.mymodule models.py e genera l'errore sopra riportato. Questo può essere risolto non includendo il modulo principale nell'elenco INSTALLED_APPS:

'myapp.module',

Includere myappinvece di myapp.modulecausa la creazione di tutte le tabelle del database con nomi errati, quindi questo sembra essere il modo corretto di farlo.

Mi sono imbattuto in questo post mentre cercavo una soluzione a questo problema, quindi ho pensato di metterlo qui :)


0

Basta aggiungere alla risposta della Giordania (grazie per la punta Giordania) può succedere anche se importi il ​​livello sopra le app e quindi importa le app, ad es.

myproject/ apps/ foo_app/ bar_app/

Quindi se stai importando app, foo_app e bar_app, potresti avere questo problema. Avevo app, foo_app e bar_app tutte elencate in settings.INSTALLED_APPS

E vuoi evitare comunque di importare app, perché hai la stessa app installata in 2 spazi dei nomi diversi

apps.foo_app e foo_app

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.