Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django models: Why the name clash?

Firstly, I know how to fix the problem, I'm just trying to understand why it's occuring. The error message:

users.profile: Reverse query name for field 'address' clashes with related field 'Address.profile'. Add a related_name a rgument to the definition for 'address'.

And the code:

class Address(models.Model):
    country = fields.CountryField(default='CA')
    province = fields.CAProvinceField()
    city = models.CharField(max_length=80)
    postal_code = models.CharField(max_length=6)
    street1 = models.CharField(max_length=80)
    street2 = models.CharField(max_length=80, blank=True, null=True)
    street3 = models.CharField(max_length=80, blank=True, null=True)

class Profile(Address):
    user = models.ForeignKey(User, unique=True, related_name='profile')
    primary_phone = models.CharField(max_length=20)
    address = models.ForeignKey(Address, unique=True)

If I understand correctly, this line:

address = models.ForeignKey(Address, unique=True)

Will cause an attribute to be added to the Address class with the name profile. What's creating the other "profile" name?


What if I don't need a reverse name? Is there a way to disable it? Addresses are used for a dozen things, so most of the reverse relationships will be blank anyway.

Is there a way to copy the address fields into the model rather than having a separate table for addresses? Without Python inheritance (this doesn't make sense, and if an Model has 2 addresses, it doesn't work).

like image 516
mpen Avatar asked Feb 07 '10 20:02

mpen


2 Answers

in the django docs it says:

If you'd prefer Django didn't create a backwards relation, set related_name to '+'. For example, this will ensure that the User model won't get a backwards relation to this model:

user = models.ForeignKey(User, related_name='+')

but I never tried it myself....

like image 158
adalovelace Avatar answered Nov 16 '22 14:11

adalovelace


I'm not sure where the errant profile field is coming from… But one way to find out would be: temporary remove address = models.ForeignKey(…) from Profile, ./manage.py shell, from ... import Address then see what Address.profile will tell you.

I don't think there is any official way to inherit only the fields from some other Model without using inheritance… But you could fake it like this (where SourceModel is, eg, Address and TargetModel is, eg, Profile):

for field in SourceModel._meta.fields:
    TargetModel.add_to_class(field.name, copy.deepcopy(field))

(this is coming from Django's ModelBase __new__ implementation)

like image 37
David Wolever Avatar answered Nov 16 '22 16:11

David Wolever