I want to create an object that contains 2 links to Users. For example:
class GameClaim(models.Model):
target = models.ForeignKey(User)
claimer = models.ForeignKey(User)
isAccepted = models.BooleanField()
but I am getting the following errors when running the server:
Accessor for field 'target' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'target'.
Accessor for field 'claimer' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'claimer'.
Can you please explain why I am getting the errors and how to fix them?
You have two foreign keys to User. Django automatically creates a reverse relation from User back to GameClaim, which is usually gameclaim_set. However, because you have two FKs, you would have two gameclaim_set attributes, which is obviously impossible. So you need to tell Django what name to use for the reverse relation.
Use the related_name attribute in the FK definition. e.g.
class GameClaim(models.Model):
target = models.ForeignKey(User, related_name='gameclaim_targets')
claimer = models.ForeignKey(User, related_name='gameclaim_users')
isAccepted = models.BooleanField()
The User model is trying to create two fields with the same name, one for the GameClaims that have that User as the target, and another for the GameClaims that have that User as the claimer. Here's the docs on related_name, which is Django's way of letting you set the names of the attributes so the autogenerated ones don't conflict.
The OP isn't using a abstract base class... but if you are, you will find that hard coding the related_name in the FK (e.g. ..., related_name="myname") will result in a number of these conflict errors - one for each inherited class from the base class. The link provided below contains the workaround, which is simple, but definitely not obvious.
From the django docs...
If you are using the related_name
attribute on a ForeignKey or
ManyToManyField, you must always
specify a unique reverse name for the
field. This would normally cause a
problem in abstract base classes,
since the fields on this class are
included into each of the child
classes, with exactly the same values
for the attributes (including
related_name) each time.
More info here.
Sometimes you have to use extra formatting in related_name
- actually, any time when inheritance is used.
class Value(models.Model):
value = models.DecimalField(decimal_places=2, max_digits=5)
animal = models.ForeignKey(
Animal, related_name="%(app_label)s_%(class)s_related")
class Meta:
abstract = True
class Height(Value):
pass
class Weigth(Value):
pass
class Length(Value):
pass
No clash here, but related_name is defined once and Django will take care for creating unique relation names.
then in children of Value class, you'll have access to:
herdboard_height_related
herdboard_lenght_related
herdboard_weight_related
I seem to come across this occasionally when I add a submodule as an application to a django project, for example given the following structure:
myapp/
myapp/module/
myapp/module/models.py
If I add the following to INSTALLED_APPS:
'myapp',
'myapp.module',
Django seems to process the myapp.mymodule models.py file twice and throws the above error. This can be resolved by not including the main module in the INSTALLED_APPS list:
'myapp.module',
Including the myapp instead of myapp.module causes all the database tables to be created with incorrect names, so this seems to be the correct way to do it.
I came across this post while looking for a solution to this problem so figured I'd put this here :)
Just adding to Jordan's answer (thanks for the tip Jordan) it can also happen if you import the level above the apps and then import the apps e.g.
myproject/
apps/
foo_app/
bar_app/
So if you are importing apps, foo_app and bar_app then you could get this issue. I had apps, foo_app and bar_app all listed in settings.INSTALLED_APPS
And you want to avoid importing apps anyway, because then you have the same app installed in 2 different namespaces
apps.foo_app
and
foo_app
Related
Considering the following models:
class ManySide(django.db.models.Model):
one_side = models.ForeignKey(
to=OneSide, on_delete=models.PROTECT, related_name="related_one_side"
)
class OneSide(django.db.models:model):
# not containing any field relevant here
def many_side_elements(self):
pass # ?
What should I include in method many_side_elements so that calling it from a OneSide Model instance would list a queryset of ManySide elements?
Official docs imply that given o is a OneSide isntance, o.many_side_set.all() should work but it returns an error in shell.
My current solution is the following:
from django.apps import apps
[...]
def many_side_elements(self):
ManySideModel = apps.get_model('<app_name_here>', 'ManySide')
val = ManySideModel.objects.filter(one_side=self)
But I'm concerned it's ineffective since it requires importing the other Model. Actually it caused a circular dependency error message in my project, hence the get_model usage.
Is there any better way? Or xy_set should work in the first place? Then what am I doing wrong?
If you create the model field with a related name, the related name overrides the _set queryset.
In your case
o.related_one_side.all() should work without the need for another def.
See: https://docs.djangoproject.com/en/4.0/topics/db/queries/#following-relationships-backward
You can override the FOO_set name by setting the related_name parameter in the ForeignKey definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries'), the above example code would look like this: b.entries.all()
I have two Django projects that communicate with each other. The first one contains model A and B that has a ForeignKey to A. The first project sends and receives serialized B objects from the second project. I want the second project to contain just B, but it needs the value of that ForeignKey. These models are defined as follows:
class A(models.Model):
...
class B(models.Model):
fk = models.ForeignKey(to='A', on_delete=models.PROTECT)
...
The problem is that ForeignKey to A in model B requires model A to be defined in the second project. Its objects also have to exist so that the database is consistent and there are no problems, e.g., in the admin panel.
In the end, I'd like to treat the fk field as a full-fledged ForeignKey in the first project and as some kind of read-only generic identifier in the second one. Specifically, I need to retain the functionality of querying both ways in the first project, e.g., fk__some_a_field and b_set. I would like to have the same code base for the model in both projects to ensure databases in the two projects stay synchronized. How can I achieve this in a clean way?
EDIT:
I was also considering fk = CustomField(...) which would be more or less defined as
if IS_FIRST_PROJECT:
CustomField = ForeignKey
else:
CustomField = IntegerField
but the issue is that I'd need a clean way to select the type of integer field that exactly matches the default foreign key. Also, I am not sure if such a solution could bring unexpected problems.
Specifically, I need to retain the functionality of querying both ways in the first project, e.g., fk__some_a_field and b_set.
If you want to use django orm, you would have to recreate your A model from project 1 in project 2. But as model A is managed by the project 1, consider adding next lines to your model in project 2:
class A(models.Model):
...
class Meta:
managed = False
db_table = 'your database table name where A model is stored'
managed=False would tell django to ignore migrations for it, and django won't be allowed to change that model's database table.
The other solution if you don't want to duplicate models from project 1 to project 2, is to not use django orm. And write sql queries by yourself. But as you mentioned you don't want to do this
P.S if you don't know how to see name of database table for model A, you can output it like this: a_model_instance._meta.db_table, or look it in some tools like pgadming if you are using postgres
I'm new to Django. In the admin panel, the name of the models has an extra "s" at the end. How can I fix that?
Why is django-admin adding an 's'
There is a naming convention in Django the models are named in the singular. So your classes should be named:
class Comment(models.Model):
...
class Note(models.Model):
...
An instance of such a class represents a single comment, not a set of comments. Likewise consider the following
# doesn't really make sense
Comments.objects.get(...)
# reads much better
Comment.objects.get(...) #e.g. get from the comment objects
This is so much of a convention that Django admin expects for your classes to be named in the singular. For this reason, Django adds on an 's' as a standard way of pluralising your class names. (This will admittedly not work for all words and is very anglo-centric, but as an override, Django provides the verbose_name_plural meta-attribute).
How to fix it:
Rename your classes so they are in the singular. This will make your code a lot more readable to anyone who is used to reading django. It will also make your models named in a way consistent with other third-party packages. If your class names are not in English, or do not pluralise simply by appending an s, use verbose_name_plural e.g:
Class Cactus(models.Model):
class Meta:
verbose_name_plural = 'Cacti'
Add a meta class to your model and set verbose_name_plural (https://docs.djangoproject.com/en/3.2/ref/models/options/#verbose-name-plural). Ideally name your classes as singular (in this case you'd have class Comment(models.Model).
class Comments(models.Model):
class Meta:
verbose_name_plural = 'Comments'
Good read:
https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html#:~:text=Always%20name%20your%20models%20using,not%20a%20collection%20of%20companies.
Is it possible without related name (related_name="+") to prefetch objects on the target instance? Sure I know it's not a problem with the related name, but I'm not really sure if it's possible without it.
Here is the example code:
from django.db import models
class Parent(models.Model):
name = models.CharField(max_length=50)
class Child(models.Model):
parent = models.ForeignKey(to=Parent, related_name="+", on_delete=models.CASCADE)
name = models.CharField(max_length=50)
Parent.objects.all().prefetch_related('child_set')
Maybe it's possible using the Prefetch(lookup, queryset=None, to_attr=None) object, because it takes the queryset in the argument list?
Looked through the code a bit and found this line:
rel_obj_descriptor = getattr(instance.__class__, through_attr, None)
Here instance is the model instance, and through_attr is the field name of related instance to be fetched. This line basically tries to get a related descriptor to perform the prefetch query. In your case rel_obj_descriptor would contain None.
To answer your question no it is not possible at least for a Foreign Key, there may be some hack for Many to Many relationships as Django appears to use some internal descriptors for them.
I would advice you to simply not set related_name="+" since you want to use the backwards relation here. You say "It's because of separation of concerns between multiple apps" but that does not make much sense. Don't we set a foreign key to the user model for various other models anyway and still use the related name? Does the point of separation of concerns arise there(the user model is in a separate app)?
try
parent = Parent.objects.get(id=pk)
parent.child_set.all()
I don't know if having related_name = '+' prevents this situation, but if you never define related_name, you can definitely use this method.
What is the preferred naming convention for Django model classes?
Django models are just Python classes, so the Python naming conventions detailed in PEP-8 apply.
For example:
Person
Category
ZipCode
If Django fails to pluralize the class name properly when creating the corresponding table, you can easily override the pluralization by setting a custom verbose_name_plural field in an inner META class. For example:
class Story(models.Model):
...
class Meta:
verbose_name_plural = "stories"
As far as I know, the idea is that the class name should be singular and should use SentenceCase with no spaces. So you'd have names like:
Person
TelephoneNumber
Then the Django admin tool knows how to pluralise them. Doesn't work so nicely for names like:
Category
which gets pluralised as Categorys, but there we go...
Apart from that, just give it a name that means something to you and succinctly sums up what the class is meant to represent.
Ben
In most of programming languages, people prefer give a singular names to the objects/models because these models are also represented by tables in your database system. The minimalism is a good choice everytime to avoid some meaning conflicts in the future.
To exemplify;
https://stackoverflow.com/a/5841297/2643226
In adition, when you need related objects for a Model of more than one word, you can use the _set attribute. Example:
class ProcessRoom(models.Model):
...
plant = models.ForeignKey("Plant", verbose_name='planta', on_delete=models.CASCADE)
Then, related objects will be:
plant = Plant.object.get(id=1)
process_rooms = plant.processroom_set.all