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
Related
I have two models: Setting and SettingsGroup.
When someone clicks on a specific SettingsGroup in the Django Admin and the edit/detail page appears I'd like for the child Setting objects to be displayed but as a list not a form.
I know that Django has InlineModelAdmin but this displays the children as editable forms.
My concern isn't with the child objects being editable from the parent object but rather the amount of space it consumes. I'd rather have a list with either a link to the appropriate child record or that changes a particular object to be inline editable.
Here is my Setting model:
class Setting(models.Model):
key = models.CharField(max_length=255, blank=False)
value = models.TextField(blank=True)
group = models.ForeignKey('SettingsGroup', blank=True,
on_delete=models.SET_NULL, null=True)
def __str__(self):
return str(self.key)
And the SettingsGroup model:
class SettingsGroup(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
def __str__(self):
return str(self.name)
The method I don't want to use (or need to find a different way to use) is InlineModelAdmin which appears in my admin.py currently as:
class SettingsGroupInline(admin.StackedInlin):
model = Setting
fk_name = 'group'
#admin.register(SettingsGroup)
class SettingsGroupAdmin(admin.ModelAdmin):
inlines = [ SettingGroupsInline, ]
Here is an example of how I'd like it to work:
There is a MySettings object, an instance of the SettingsGroup model.
There is a CoolSetting object and a BoringSetting object, each an instance of the Setting model.
The CoolSetting object has its group set to the MySettings object.
The BoringSetting object does not have a group set.
When I open the detail/edit view of the Django Admin for the MySettings object I see the normal edit form for the MySettings object and below it the CoolSetting object (but not as a form).
I do not see the BoringSetting object because it is not a child/member/related of/to MySettings.
I have some ideas on how this could be accomplished but this seems like fairly basic functionality and I don't want to go building something if Django (or other existing code) provides a way to accomplish this.
Any ideas?
Why can't you just access the children using something like Setting.objects.filter(group=SettingsGroup.objects.get(name={name}))
If being presented in a template you could pass the SettingsGroup name to the context and iterate over the children and present them however you like.
I may not understand your question exactly so if this is not what you're looking for let me know!
How do I check if there are any ManyToMany field objects related to my model object?
For example, I have a model:
class Category(models.Model):
related_categories = models.ManyToManyField('self', blank=True)
I want to do something only if there are related objects existing:
if example_category.related_categories:
do_something()
I tried to do example_category.related_categories, example_category.related_categories.all(), example_category.related_categories.all().exists(), example_category.related_categories.count(), but none of these works for me.
I have no any additional conditions to filter by.
Is there any easy way to check emptiness of this field?
you should use the .exists method:
related_categories = example_category.related_categories
if related_categories.exists():
# do something
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()
Class Folder inherits from class Item, which has a foreign key to Folder:
class Item(models.Model):
# some fields
folder = models.ForeignKey('Folder')
class Folder(Item):
# some fields
When I try to run this, I get the error:
app.item: 'folder' has a relation with model Folder, which has either not been installed or is abstract
I thought the correct thing to do here was to put the model name in quotes, which I have done, but it doesn't seem to help. What should I do to make this work?
Edit: Clarified question using meaningful class names
I have Items (A), some of which are Folders (B). I want both classes
to have a reference to at most one Folder
It doesn't make much sense(to me) what you're trying to do but this can be achieved
as follows:
class Item(models.Model):
# some fields
is_folder = models.BooleanField(default=False)
some_other_folder = models.ForeignKey('self', null=True, blank=True)
And then check with python code that if is_folder==False, that some_other_folder
is not None(null).
So actually you don't need 2 models.
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')