I have this model:
class Person(models.Model):
something ...
employers = models.ManyToManyField('self', blank=True, related_name='employees')
When I do person.employees.all() I get this error: 'Person' object has no attribute 'employees'. Is the related name only created when there is an actual link in place. If yes, how can I check this?
EDIT: I'm aware of the hasattr() function. I'm still wondering why the attribute doesn't return an empty list when there's no related objects.
To use related_name with recursive many-to-many you need set symmetrical=False. Without it Django will not add employees attribute to the class. From the docs:
When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it doesn’t add a person_set attribute to the Person class. Instead, the ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
So you can add symmetrical=False to the field:
employers = models.ManyToManyField('self', blank=True, related_name='employees', symmetrical=False)
person.employees.all() # will work now
or just use employers attribute:
person.employers.all()
Related
I'd like to create a many-to-many relationship from and to a user class object.
I have something like this:
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField(MyUser, blank=True, null=True)
The question is if I can use the class reference inside itself. Or do I have to use "self" insead of "MyUser" in the ManyToManyField? Or is there another (and better) way to do it?
Technically, I'm pretty sure "MyUser" or "self" will work, as long as it's a string in either case. You just can't pass MyUser, the actual class.
However, the docs always use "self". Using "self" is not only more explicit about what's actually happening, but it's impervious to class name changes. For example, if you later changed MyUser to SomethingElse, you would then need to update any reference to "MyUser" as well. The problem is that since it's a string, your IDE will not alert you to the error, so there's a greater chance of your missing it. Using "self" will work no matter what the class' name is now or in the future.
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField("self", blank=True)
Don't forget use symmetrical=False, if you use .clear() or .add() method for related objects and don't wanna object on other side of relation update own data in relation field.
some_field = models.ManyToManyField('self', symmetrical=False)
I think it should be class name instead of self. because with using self like this
parent = models.ManyToManyField('self', null=True, blank=True)
when i add parent:
user1.parent.add(user2)
i have 2 record in database like this:
and with using class name liken this:
parent = models.ManyToManyField('User', null=True, blank=True)
i have one record in database like this:
note that i use uuid for pk and i use django 3.1
EDIT:
as #shinra-tensei explained as comment in this answer we have to set symmetrical to False if we use self. documented in Django Documents: ManyToManyField.symmetrical
If you use self or MyUser you will get a NameError in both cases. You should write "self" as string. See the example below:
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField("self", blank=True, null=True)
And do not forget to set the symmetrical attribute to False if the relationship is not symmetrical.
For further details check: https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ManyToManyField
don't use 'self' in ManyToManyField, it will cause you object link each other, when use django form to submit it
class Tag(models.Model):
...
subTag = models.ManyToManyField("self", blank=True)
...
aTagForm.save()
and result:
a.subTag == b
b.subTag == a
I want to have two foreign keys to the same model:
class Test(models.model):
example1 = models.ForeignKey(Example)
example2 = models.ForeignKey(Example)
I get errors like:
Accessor for field 'example1' clashes with related
field 'Example.test_set'. Add a related_name argument
to the definition for 'example1'.
Try using related_name:
class Test(models.model):
example1 = models.ForeignKey('Example', related_name='example1')
example2 = models.ForeignKey('Example', related_name='example2')
Django uses some python magic to define relationships between models, some of which involves using the name of the models in the relationships (that's where the 'test' in 'test__set' is coming from.) What's happening, I would guess, is that it's trying to put "test__set" in the Example model twice, once for each foreign key you've got defined.
The error message suggests something to try: define a related_name argument (overriding one of those 'test_set's) that it can use instead of auto-generating two clashing names.
More info here: page has been removed
Current page relating to model relationships:
https://docs.djangoproject.com/en/2.0/ref/models/fields/#module-django.db.models.fields.related
Just do what the error message tells you to do, and if you're unsure what that means, consult the documentation for related_name.
In django 2.0 Try this:
user = models.ForeignKey(User, on_delete=models.PROTECT, null=True, related_name='user')
paper = models.ForeignKey(paperRecord, on_delete=models.PROTECT, null=True, related_name='paper')
Text below is from Django docs which provide
To create a recursive
relationship – an object that has a many-to-one relationship with itself – use models.ForeignKey(’self’).
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model,
rather than the model object itself.
can someone give me an example of the usage of these capabilities in Django?
Thanks
You can use it to create links to other objects of this Model.
For example if you have many members in a website and each has an inviter (also of Member type) you can do the following:
class Member(Model):
inviter = models.ForeignKey(
'self',
related_name="invited_set"
)
If you want the inviter, you do:
Member.objects.get(id__exact=5).inviter
If you want all members that this member has invited you use:
Member.objects.get(id__exact=5).invited_set
For models not yet defined:
class Gallery(models.Model):
title_image = models.ForeignKey('Image')
class Image(models.Model):
part_of = models.ForeignKey(Gallery)
since these classes refer to each other, at least one of them needs to refer to a class not yet defined.
I recently got a ForeignKey clash in my Django model. I have the need to have two foreign keys (owner, assigned_to) ultimately pointing to the same model (a user).
From what I understand I need a related_name argument to solve that problem. So I did that:
assigned_to = models.ForeignKey(TaskUser, blank=True, null=True, related_name='user_assignment')
and
owner = models.ForeignKey(TaskUser, related_name="user_ownership"
But I'm still getting an error:
tasks.task: Accessor for field 'owner' clashes with related field 'TaskUser.user
_ownership'. Add a related_name argument to the definition for 'owner'.
tasks.task: Reverse query name for field 'owner' clashes with related field 'TaskUser.user_ownership'. Add a related_name argument to the definition for 'owner'.
Why am I still getting this error?
There is one catch, owner is in a super class (BaseWidget) and assigned_to is in a sub class (Task). Are there issues with using related_name in an inheritance relationship? Do I need to just override the inheritance of owner and redefine related_name in the sub class instead? I'd appreciate any help!
If you have ForeignKey relationships in an abstract base class every class inheriting from it will have this relationship. As a result of this you must not 'hardcode' its related_name, because all sub classes will try to create the same accessor on the realted class (TaskUser in this case).
You should better do something like:
owner = models.ForeignKey(TaskUser, related_name="%(app_label)s_%(class)s_ownership")
See the django docs on this.
If you are using related_name in abstract base class you need to use a '%(app_label)s' and '%(class)s' in it.
Its mentioned in django doc
Be careful with related_name
First of all,I'm not into web programming. I bumped into django and read a bit about models. I was intrigued by the following code ( from djangoproject.com ) :
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
# Note use of django.utils.encoding.smart_str() here because
# first_name and last_name will be unicode strings.
return smart_str('%s %s' % (self.first_name, self.last_name))
By my understanding of python , first_name and last_name are class variables , right ? How is that used in code ( because I guess that setting Person.first_name or Person.last_name will affect all Person instances ) ? Why is it used that way ?
The essence of your question is "how come these class variables (which I assign Field objects to) suddenly become instance variables (which I assign data to) in Django's ORM"? The answer to that is the magic of Python metaclasses.
A metaclass allows you to hook into and modify the process of creating a Python class (not the creation of an instance of that class, the creation of the class itself).
Django's Model object (and thus also your models, which are subclasses) has a ModelBase metaclass. It looks through all the class attributes of your model, and any that are instances of a Field subclass it moves into a fields list. That list is assigned as an attribute of the _meta object, which is a class attribute of the model. Thus you can always get to the actual Field objects via MyModel._meta.fields, or MyModel._meta.get_field('field_name').
The Model.__init__ method is then able to use the _meta.fields list to determine what instance attributes should be initialized when a model instance is created.
Don't be afraid to dive into the Django source code; it's a great source of education!
Yes, first_name and last_name are class variables. They define fields that will be created in a database table. There is a Person table that has first_name and last_name columns, so it makes sense for them to be at Class level at this point.
For more on models, see:
http://docs.djangoproject.com/en/dev/topics/db/models/
When it comes to accessing instances of a Person in code, you are typically doing this via Django's ORM, and at this point they essentially behave as instance variables.
For more on model instances, see:
http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs
Not a real answer, but for enrichment:
Person.first_name
won't work
p = Person.objects.get(pk=x)
p.first_name
will work. so an object instance of person has a first and last name, but static context Person does not.
Also note: Django has Model Managers which are allow "Person" to do static queryset operations. (https://docs.djangoproject.com/en/dev/topics/db/managers/#managers).
so for example
peoples = Person.objects.all()