/ / django ereditarietà multipla - django, modelli django, ereditarietà django

eredità multipla di django - django, modelli di django, ereditarietà di django

Attualmente sto lavorando a un progetto Django in cuibisogno di fare eredità multipla. Il progetto in sé ha un amministratore con più siti Web. Nella mia parte di amministratore ho creato una classe Member contenente tutte le informazioni obbligatorie per un membro. Quindi tutti i singoli siti hanno una classe MemberExtra creata dalla classe Member dall'amministratore in cui aggiungo tutte le informazioni complementari. Quando avvio il mio server (Python Manage .py RunServer ...) Ho quell'errore:

Error: One or more models did not validate:
programsite.memberextra: Accessor for field "member_ptr" clashes with related field "Member.memberextra". Add a related_name argument to the definition for "member_ptr".
programsite.memberextra: Reverse query name for field "member_ptr" clashes with related field "Member.memberextra". Add a related_name argument to the definition for "member_ptr".
gourmandiz.memberextra: Accessor for field "member_ptr" clashes with related field "Member.memberextra". Add a related_name argument to the definition for "member_ptr".
gourmandiz.memberextra: Reverse query name for field "member_ptr" clashes with related field "Member.memberextra". Add a related_name argument to the definition for "member_ptr".

admin / models.py:

class Member(models.Model):
prog = models.ForeignKey(Program, verbose_name=_("Program"))
status = models.CharField(_("Status"), m    status = models.CharField(_("Status"), max_length=1, choices=STATUS_CHOICE
S)
points_avai = models.BigIntegerField(_("
Current Points"), null=True)
points_notavai = models.BigIntegerField(_("Future Points"), null=True)
cn = models.CharField(_("Company name"), max_length=250)
full_name = models.CharField(_("Full name"), max_length=250)
b_add = models.CharField(_("Billing address"), max_length=250)
b_city = models.CharField(_("Billing City"), max_length=250)
b_zip = models.CharField(_("Billing ZIP code"), max_length=250)
b_country = models.CharField(_("Billing country"), max_length=250)
prog_start_date = models.DateField(_("Program start date"), null=True)
prog_end_date = models.DateField(_("Program end date"), null=True)
member_id = models.CharField(_("Member ID"), max_length=250, primary_key=T
rue)
client_id = models.CharField(_("Client ID"), max_length=250, help_text="Nu
méro de client.")
user = models.OneToOneField(User)

def __unicode__(self):
return self.full_name + " (" + str(self.member_id) + ")"

class Meta:
verbose_name = _("Member")
verbose_name_plural = _("Members")

programsite / models.py:

class MemberExtra(Member):
email = models.EmailField(_("Email"), max_length=100, null=True)
tel = models.CharField(_("Tel"), max_length=100, null=True)
patrick = models.CharField(_("Patrick"), max_length=100, null=True)
test42 = models.CharField(_("Test42"), max_length=100, null=True)

gourmandiz / models.py:

class MemberExtra(Member):
email = models.EmailField(_("Email"), max_length=100, null=True)

risposte:

2 per risposta № 1

Il problema qui è che erediti il ​​tuo modello due volte ed entrambi i modelli figlio hanno lo stesso nome. Ciò comporta il doppio dello stesso nome_relativo, il che è un problema per Django.

La tua soluzione da aggiungere

member = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")"

nel tuo MemberExtra il modello funziona, ma perdi la magia dell'ereditarietà implicita che Django fa per permetterti di accedere a entrambi i tuoi modelli in uno:

Con la tua soluzione devi fare:

from programsite.models import MemberExtra
m = MemberExtra.objects.get(member__full_name = "Foobar")
m.email # -> returns the email of your MemberExtra instance
m.member.b_add # -> returns the address of the inherited member instance

Dove, con l'eredità nativa di Django, puoi fare:

from programsite.models import MemberExtra
m = MemberExtra.objects.get(full_name = "Foobar")
m.email # -> returns the email of your MemberExtra instance
m.b_add # -> returns the address of the inherited member instance

Il che è molto più pulito secondo me.

Per gestire l'eredità, Django crea effettivamente un OneToOneField (https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance). Questo campo è chiamato <parentclass>_ptr, member_ptr nel tuo caso.

Se si crea manualmente un OneToOneField di nome <parentclass>_ptre assegnagli un nome_relativo, Django è ancora in grado di trovare il modello principale e non si lamenterà di nomi_identici identici.

Nel tuo caso, basta aggiungere

member_ptr = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")"

in entrambi i tuoi MemberExtra definizioni del modello. </ Strike>

Questa soluzione funziona, ma non è come dovrebbe essere fatta. Django fornisce una bandiera parent_link che, se impostato su true, dirà a Django che questo è il campo che verrà utilizzato per accedere alla classe genitore.

Quindi puoi aggiungere un campo

member = models.OneToOneField(Member, parent_link=True, related_name="%(app_label)s_%(class)s_related")"

che funzionerà comunque se, per qualche motivo, Django deve rinominare il puntatore predefinito sul genitore.


1 per risposta № 2

Il related_name per un FK deve essere unico. Quando hai un FK con un valore predefinito related_name (non specificato), ereditato da più altri modelli, tutti i modelli finiscono con lo stesso related_name. Vedi la sezione dei documenti Django intitolata Stai attento related_name.

La soluzione è impostare il related_name argomento dell'FK a qualcosa del genere:

prog = models.ForeignKey(Program, verbose_name=_("Program"), related_name="%(app_label)s_%(class)s_related")

Django sottoporrà quindi l'etichetta dell'app e il nome del modulo alla stringa, rendendo il file related_name unico per ciascuna delle sottoclassi.