I am trying to create a db model using django inspect db and it is generating all the models but I am getting error.
I am using this command to generate db models for existing database:
python manage.py inspectdb > models.py
It is generating models accurately but in fileds such as this:
create_uid = models.ForeignKey('self', models.DO_NOTHING,db_column='create_uid', blank=True, null=True)
write_uid = models.ForeignKey('self',models.DO_NOTHING, db_column='write_uid', blank=True, null=True)
I am getting error:
polls.ResUsers.create_uid: (fields.E304) Reverse accessor for 'ResUsers.create_uid' clashes with reverse accessor for 'ResUsers.write_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.create_uid' or 'ResUsers.write_uid'.
polls.ResUsers.write_uid: (fields.E304) Reverse accessor for 'ResUsers.write_uid' clashes with reverse accessor for 'ResUsers.create_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.write_uid' or 'ResUsers.create_uid'.
I am adding related names like this:
create_uid = models.ForeignKey('self', models.DO_NOTHING,related_name='create_uid',db_column='create_uid', blank=True, null=True)
What should I do in order to use generated models. I am using postgres.
I am updating my question one of the answer worked for me when I am using it like this:
create_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
In one other model class when I am using this code like this:
create_uid = models.ForeignKey(
'ResUsers',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
I am getting the error:
polls.ResUsers.create_uid: (fields.E304) Reverse accessor for 'ResUsers.create_uid' clashes with reverse accessor for 'SurveyUserInput.create_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.create_uid' or 'SurveyUserInput.create_uid'.
The related_name=… [Django-doc] is the name of the relation in reverse. So it is meant to access all model objects with as create_uid/write_uid the object. This can result in a QuerySet of zero, one or more elements.
Therefore the related_names of two ForeignKeys to the same model, can not be the same, since that would make the model ambiguous. Since your ForeignKeys refer to the 'self' model, you can not even given these the name of a field that already exists.
You thus might want to give the relations a name like:
class MyModel(models.Model):
create_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
write_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='write_uid',
related_name='written_items',
blank=True,
null=True
)
Related
I've recieved the following error and I'm not sure how to handle this in my model.
HINT: Add or change a related_name argument to the definition for 'UserCart.state_tax' or 'UserCart.fed_tax'.
userorders.UserCart.state_tax: (fields.E304) Reverse accessor for 'UserCart.state_tax' clashes with reverse accessor for 'UserCart.other_tax'.
models.py
class UserCart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
state_tax = models.ForeignKey(Tax, on_delete=models.SET_NULL, null=True)
fed_tax = models.ForeignKey(Tax, on_delete=models.SET_NULL, null=True)
This is here necessary, since you have two references from UserCart to the Tax model. This thus means that the relation in reverse (from Tax to UserCart) can not be usercart_set, since then it is not clear which relation we use in reverse.
We thus should at least give a related name to one of the relations (that is different from usercart_set). For example:
from django.contrib.auth import get_user_model
class UserCart(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, default=None)
state_tax = models.ForeignKey(
Tax,
related_name='state_usercarts',
on_delete=models.SET_NULL,
null=True
)
fed_tax = models.ForeignKey(
Tax,
related_name='fed_usercarts',
on_delete=models.SET_NULL,
null=True
)
Note: you might want to make use of get_user_model [Django-doc] over a reference to User itself. If you later change your user model, then the ForeignKey will automatically refer to the new user model.
How do you define the reverse relation from another object to this one with a '+' as it's related name?
class FeaturedContentPage(Page):
featured_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
The idea of a related_name*ending with a '+' is to disable creating a reverse relation, as is documented:
If youd prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'.
You can of course still query in reverse with:
FeaturedContentPage.objects.filter(featured_page=my_page)
But there is thus no relation constructed in reverse, so my_page.featuredcontentpage_setis not accessible.
the related_name argument is used for reverse relation name . if a model has 2 field referencing the same model
featured_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
regular_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
without related_name='+' django will complain because it use wagtailcore.Page model name for reverse relation. as two attribute in object can not have same name by setting related_name='+' to one or both field will ignore creating reverse relation .
class Professional(models.Model):
...
favoriting_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='favorites.FavoriteProfessional')
recommending_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='recommendations.ProfessionalRecommendation')
I get no errors when I delete on of the ManyToMany fields. However, I get SystemCheckError when I run 'python manage.py makemigrations'.
ERRORS:
professionals.Professional.favoriting_customers: (fields.E304) Reverse accessor for 'Professional.favoriting_customers' clashes with reverse accessor for 'Professional.recommending_customers'.
HINT: Add or change a related_name argument to the definition for 'Professional.favoriting_customers' or 'Professional.recommending_customers'.
professionals.Professional.recommending_customers: (fields.E304) Reverse accessor for 'Professional.recommending_customers' clashes with reverse accessor for 'Professional.favoriting_customers'.
HINT: Add or change a related_name argument to the definition for 'Professional.recommending_customers' or 'Professional.favoriting_customers'.
As suggested by the HINT, you need to use related_name to avoid clashes on backward relations. You are going to need this every time you have two fields in the same model with a relation to the same object (customers.Customer in your case).
You can try something like this:
class Professional(models.Model):
...
favoriting_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='favorites.FavoriteProfessional',
related_name='favorites'
)
recommending_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='recommendations.ProfessionalRecommendation',
related_name='recommendations'
)
If you are not interested in backward relation to Professional table, you can disable it by using '+' as the related_name:
class Professional(models.Model):
...
favoriting_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='favorites.FavoriteProfessional',
related_name='+'
)
recommending_customers = models.ManyToManyField(
'customers.Customer', blank=True,
through='recommendations.ProfessionalRecommendation',
related_name='+'
)
Also, you should be careful with related_name
I need to store the relations between people. So I have the following models
class Person(models.Model):
name = models.CharField(max_length=255, blank=True)
parents = models.ManyToManyField('self', through='PersonRelationship', symmetrical=False, blank=True, related_name="person_parents_set")
friends = models.ManyToManyField('self', through='PersonRelationship', symmetrical=False, blank=True, related_name="person_friends_set")
class PersonRelationship(models.Model):
from_person = models.ForeignKey(Person, related_name="from_persons")
to_person = models.ForeignKey(Person, related_name="to_persons")
relation_start = models.DateField(blank=True)
relation_end = models.DateField(blank=True)
When I try to syncdb I get this error:
Error: One or more models did not validate:
films.person: The model Person has two manually-defined m2m relations through the model PersonRelationship, which is not permitted. Please consider using an extra field on your intermediary model instead.
I guess I cannot have two m2m relationships trough the same model, so I tried to create a model for each type of relation, to avoid repeating myself I used a abstract model like this:
class PersonRelationship(models.Model):
from_person = models.ForeignKey(Person, related_name="from_persons")
to_person = models.ForeignKey(Person, related_name="to_persons")
relation_start = models.DateField(blank=True)
relation_end = models.DateField(blank=True)
class Meta:
abstract = True
class PersonParent(PersonRelationship):
pass
class PersonFriend(PersonRelationship):
pass
And I'm getting this error, but I already have a related_name:
films.personparent: Accessor for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Reverse query name for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Accessor for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Reverse query name for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
Any help would be appreciated.
I just found the solution, I am posting it in case somebody coming from google had found the same issue.
Read this link [link updated to v1.9]:
https://docs.djangoproject.com/en/1.9/topics/db/models/#be-careful-with-related-name
So I just changed the related name to:
from_person = models.ForeignKey(Person, related_name="%(app_label)s_%(class)s_from_persons")
to_person = models.ForeignKey(Person, related_name="%(app_label)s_%(class)s_to_persons")
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).
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....
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)
I don't think it's possible to disable the reverse name.
I've just done a quick grep over the code and it doesn't look like there is any logic which will bypass setting up the related_name field on the related model.
For Example: Add just '+'
class GeneralConfiguration(models.Model):
created_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
updated_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')