/ herança múltipla / django - django, modelos de django, herança de django

herança múltipla do django - django, modelos-django, herança do django

Atualmente, estou trabalhando em um projeto de django onde euprecisa fazer vários legados. O projeto em si tem um administrador com vários sites. Na minha parte administrativa, criei uma classe Member contendo todas as informações obrigatórias para um membro. Em seguida, todos os sites individuais têm uma classe MemberExtra criada a partir da classe Member do administrador, onde adiciono todas as informações complementares. Quando inicio meu servidor (python manage .py runserver ...) Eu tenho esse erro:

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)

Respostas:

2 para resposta № 1

O problema aqui é que você herda seu modelo duas vezes e os dois modelos filhos têm o mesmo nome. Isso resulta em ter o dobro do mesmo nome_relacionado, o que é um problema para o Django.

Sua solução para adicionar

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

na tua MemberExtra O modelo funciona, mas você perde a mágica implícita de herança que o Django faz para permitir que você acesse os dois modelos em um:

Com sua solução, você precisa:

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

Onde, com a herança nativa do Django, você pode:

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

O que é muito mais limpo na minha opinião.

Para gerenciar a herança, o Django realmente cria um OneToOneField (https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance) Este campo é chamado <parentclass>_ptr, member_ptr no seu caso.

Se você criar manualmente um OneToOneField nomeado <parentclass>_ptre atribua a ele um_nome_relacionado, o Django ainda poderá encontrar o modelo-pai e não reclamará de nomes-relacionados idênticos.

No seu caso, basta adicionar

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

tanto no seu MemberExtra definições de modelo. </ strike>

Esta solução funciona, mas não é como deve ser feita. Django fornece uma bandeira parent_link que, quando definido como true, dirá ao Django que este é o campo que será usado para acessar a classe pai.

Então você pode adicionar um campo

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

que ainda funcionará se, por alguma razão, o Django precisar renomear o ponteiro padrão para o pai.


1 para resposta № 2

o related_name para um FK tem que ser único. Quando você tem um FK com um padrão related_name (não especificado), herdado por vários outros modelos, todos os modelos terminam com o mesmo related_name. Veja a seção nos documentos do Django intitulada Seja cuidadoso com related_name.

A solução é definir o related_name argumento do FK para algo como:

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

O Django submarca o rótulo do aplicativo e o nome do módulo para a string, fazendo o related_name exclusivo para cada uma das subclasses.