How can I define the ManyToManyField name in django?
Question:
I have this relationship
Class Item(models.Model):
pass
Class Category(models.Model):
items = models.ManyToManyField(Item)
I can define the field name as items
for category and access it via category.items
but I want to define a field name for Item too as item.categories
rather than the default item.category
How can I achieve it?
Update
Tried
items = models.ManyToManyField(Item, related_name = "categories")
But I get
TypeError: Direct assignment to the reverse side of a many-to-many set is prohibited. Use categories.set() instead.
on Item.object.create(**data)
Answers:
See, ManyToManyField can’t make reverse relationship with related model as python is interpreted language, so it can’t read model class of previous one. Instead, you can do one thing …
# models.py
class Item(models.Model):
item_name = models.CharField(max_length=255, default="")
def __str__(self):
return self.item_name
class Category(models.Model):
category_name = models.CharField(max_length=255, default="")
items = models.ManyToManyField(Item)
def __str__(self):
return self.category_name
After that, you can list down your requirements in views.py file.
# views.py
def get_items_by_categories(request):
# Here, you will receive a set of items ...
get_categories = Category.objects.all()
# Filter out items with respect to categories ...
get_items_list = [{"category": each.category_name, "items": each.items} for each in get_categories]
return render(request, "categories.html", {"data": get_items_list})
Iterate your items with categories in categories.html file.
{% for each in data %}
{% for content in each %}
{{content.category}}
{% for item in content.items.all %}
{{item.item_name}}
{% endfor %}
{% endfor %}
{% endfor %}
I hope this solution will help you ..
Thank You !
The thing about many to many field is not an actual field. If you take a look at the generated schema you wouldnt find the field as a column in either of the table. What happens in the back is django creates a ItemCatagory
table.
class ItemCatagory(models.Model):
item = modes.ForegnKeyField(Item, related_name="catagories", on_delete... )
catagory = models.ForegnKeyField(Item, related_name="items", on_delete... )
catagory.items
will give u the ItemCatagory
RelatedObject
and if u do catagoty.items.all()
it will give u QuerySet[ItemCatagory]
. so the default model.save()
method woont add those rship. so u would have to overide save
method on either of the models.
When you call Item.objects.create()
, you need to omit the categories
from the args. Then afterwards you can call set()
to set the categories.
item = Item.objects.create()
item.categories.set(categories)
If you want to add to existing categories (rather than overwriting what’s there), call add()
instead:
item = Item.objects.create()
item.categories.add(category)
Note: both add()
and set()
save the update to the database, so you don’t need to call item.save()
afterwards
EDIT
It looks like with the default name, you can pass in a list of categories to the call to create()
and it even seems like it works because you can access the list of categories in the attribute category
:
category = Category.objects.create()
item = Item.objects.create(category=[category])
print(item.category)
# output: [<Category: Category object(1)>]
The problem with this is category
is not how you set or access category objects on an item, it’s category_set
, and that’s empty.
To see this, after running the above code fetch the item
from the database, you can see that the category is not associated with the item (it wasn’t saved):
item = Item.objects.get(id=item.id)
print(item.category_set)
# output: []
(And if you try to do item.category
, you get an attribute error.)
It’s confusing that Django lets you provide the category
argument in a call to create() with the default related name, but fails with an error when the related_name is set. IMO it should have an error in both cases, because clearly passing an m2m list as an argument to create()
does not work: you have to call set()
or add()
.
Source: Many-to-Many relations
I have this relationship
Class Item(models.Model):
pass
Class Category(models.Model):
items = models.ManyToManyField(Item)
I can define the field name as items
for category and access it via category.items
but I want to define a field name for Item too as item.categories
rather than the default item.category
How can I achieve it?
Update
Tried
items = models.ManyToManyField(Item, related_name = "categories")
But I get
TypeError: Direct assignment to the reverse side of a many-to-many set is prohibited. Use categories.set() instead.
on Item.object.create(**data)
See, ManyToManyField can’t make reverse relationship with related model as python is interpreted language, so it can’t read model class of previous one. Instead, you can do one thing …
# models.py
class Item(models.Model):
item_name = models.CharField(max_length=255, default="")
def __str__(self):
return self.item_name
class Category(models.Model):
category_name = models.CharField(max_length=255, default="")
items = models.ManyToManyField(Item)
def __str__(self):
return self.category_name
After that, you can list down your requirements in views.py file.
# views.py
def get_items_by_categories(request):
# Here, you will receive a set of items ...
get_categories = Category.objects.all()
# Filter out items with respect to categories ...
get_items_list = [{"category": each.category_name, "items": each.items} for each in get_categories]
return render(request, "categories.html", {"data": get_items_list})
Iterate your items with categories in categories.html file.
{% for each in data %}
{% for content in each %}
{{content.category}}
{% for item in content.items.all %}
{{item.item_name}}
{% endfor %}
{% endfor %}
{% endfor %}
I hope this solution will help you ..
Thank You !
The thing about many to many field is not an actual field. If you take a look at the generated schema you wouldnt find the field as a column in either of the table. What happens in the back is django creates a ItemCatagory
table.
class ItemCatagory(models.Model):
item = modes.ForegnKeyField(Item, related_name="catagories", on_delete... )
catagory = models.ForegnKeyField(Item, related_name="items", on_delete... )
catagory.items
will give u the ItemCatagory
RelatedObject
and if u do catagoty.items.all()
it will give u QuerySet[ItemCatagory]
. so the default model.save()
method woont add those rship. so u would have to overide save
method on either of the models.
When you call Item.objects.create()
, you need to omit the categories
from the args. Then afterwards you can call set()
to set the categories.
item = Item.objects.create()
item.categories.set(categories)
If you want to add to existing categories (rather than overwriting what’s there), call add()
instead:
item = Item.objects.create()
item.categories.add(category)
Note: both add()
and set()
save the update to the database, so you don’t need to call item.save()
afterwards
EDIT
It looks like with the default name, you can pass in a list of categories to the call to create()
and it even seems like it works because you can access the list of categories in the attribute category
:
category = Category.objects.create()
item = Item.objects.create(category=[category])
print(item.category)
# output: [<Category: Category object(1)>]
The problem with this is category
is not how you set or access category objects on an item, it’s category_set
, and that’s empty.
To see this, after running the above code fetch the item
from the database, you can see that the category is not associated with the item (it wasn’t saved):
item = Item.objects.get(id=item.id)
print(item.category_set)
# output: []
(And if you try to do item.category
, you get an attribute error.)
It’s confusing that Django lets you provide the category
argument in a call to create() with the default related name, but fails with an error when the related_name is set. IMO it should have an error in both cases, because clearly passing an m2m list as an argument to create()
does not work: you have to call set()
or add()
.
Source: Many-to-Many relations