3

I'm currently working on a django project where i need to do multiple legacy. The project in it self has an admin with multiple websites. In my admin part i've created a Member class containing all mandatory info for a member. Then all individual sites have an MemberExtra class created from the Member class from the admin where i add all complementary information. When i launch my server (python manage.py runserver...) i've that error :

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)

2 Answers 2

2

The problem here is that you inherit your model twice, and both the child models have the same name. This results in having twice the same related_name, which is a problem for Django.

Your solution to add

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

in your MemberExtra model works, but you loose the implicit inheritance magic that Django do to let you access both your models in one:

With your solution you have to do:

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

Where, with the Django native inheritance, you can do:

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

Which is much cleaner in my opinion.

To manage the inheritance, Django actually creates a OneToOneField (https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance). This field is called <parentclass>_ptr, member_ptr in you case.

If you manually create a OneToOneField named <parentclass>_ptr, and give it a related_name, Django is still able to find the parent model, and will not complain about identical related_names.

In your case, just add

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

in both your MemberExtra model definitions.

This solution works, but is not how it should be done. Django provides a flag parent_link that, when set to true, will tell Django that this is the field that will be used to access the parent class.

So you can add a field

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

which will still work if, for some reason, Django needs to rename the default pointer to the parent.

Sign up to request clarification or add additional context in comments.

Comments

1

The related_name for a FK has to be unique. When you have an FK with a default related_name (unspecified), that is inherited by multiple other models, all of the models end up with the same related_name. See the section in the Django docs entitled Be careful with related_name.

The solution is to set the related_name argument of the FK to something like:

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

Django will then sub the app label and module name into to the string, making the related_name unique for each of the subclasses.

1 Comment

I solved my problem, i add "member = models.OneToOneField(Member, related_name="%(app_label)s_%(class)s_related")" in my "MemberExtra".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.