Many-to-Many update, Django signals - python

I have these models (simplified):
class Product(TimeStampedModel):
product_id = models.AutoField(primary_key=True, )
shop = models.ForeignKey('Shop', related_name='products', to_field='shop_name', on_delete=models.CASCADE)
category = models.ForeignKey('Category', related_name='products', to_field='category_name', on_delete=models.SET_NULL)
brand = models.ForeignKey('Brand', related_name='products', to_field='brand_name', on_delete=models.CASCADE)
class Brand(models.Model):
brand_name = models.CharField(max_length=50)
shops = models.ManyToManyField('Shop', related_name='shops')
categories = models.ManyToManyField('Category', related_name='categories')
class Category(models.Model):
category_name = models.CharField(max_length=128)
shops = models.ManyToManyField('Shop')
class Shop(models.Model):
shop_name = models.CharField(max_length=30)
In admin I am trying manually to change a Category for bunch of selected Products (I have a custom function for that). But here I see 2 problems:
1) Must be updated M2M relation in Brand->Category, if there was no Brand with this Category.
2) Must be updated M2M relation in Category->Shop, if there was not this selected Category in the Shop.
How to do this in the best way? I know that this might be some kind of Django signals use, specially m2m_changed, but I can't understand who is emitter of the signal, and who is receiver, and how to update multiple tables after change in 1 table.

Related

How to Display SubCategory Products in Django?

I have a relation between category, subcategory, and sub child category, and product is related to sub child category, but I want to display the list of subcategory products. Please let me know how I can do it.
here is my models.py file...
class Category(models.Model):
cat_name=models.CharField(max_length=225)
cat_slug=models.SlugField(max_length=225, unique=True)
class SubCategory(models.Model):
subcat_name=models.CharField(max_length=225)
subcat_slug=models.SlugField(max_length=225, unique=True)
category = models.ForeignKey('Category', related_name='subcategoryies', on_delete=models.CASCADE, blank=True, null=True)
class SubChildCategory(models.Model):
subcategory=models.ForeignKey(SubCategory, related_name='SubChildRelated', on_delete=models.CASCADE, default=None, verbose_name='Sub Category')
name=models.CharField(max_length=50, default=None)
slug=models.SlugField(unique=True, max_length=50)
here is my product models.py file...
class Product(models.Model):
name=models.CharField(max_length=225)
slug=models.SlugField(max_length=225, unique=True)
subcategory=models.ManyToManyField(SubChildCategory, related_name='pro_subchild', verbose_name='Select Category')
here is my views.py file, where I am trying to display the SubCategory product...
def home(request):
subcat_product = Product.objects.prefetch_related('subcategory')
return render(request, 'frontend/index.html',{'subcat_product':subcat_product}
but the above function is displaying all the products which are available in SubChildCategory, I want to display products according to the SubCategory on my homepage.
Please let me know what is the process to display these products.
I think it should work:
# You can also get your sub category by id
sub_child_categories = SubCategory.objects.get(
slug=your_sub_category_slug
).SubChildRelated.all()
subcat_products = Product.object.none()
for sub_child_category in sub_child_categories:
subcat_products |= sub_child_category.pro_subchild.all()
subcat_products is all the products that the a SubCategory has.

Filter and fetch using select_related and prefetch_related in django

Here are my below models:
class City(models.Model):
city = models.CharField('city name', max_length=25)
class Pincode(models.Model):
city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='city_pincode')
pincode = models.PositiveIntegerField('pincode', unique=True)
class Vendors(models.Model):
pincode = models.ManyToManyField(Pincode, related_name='pincode_vendor')
shop_name = models.CharField('Shop name(English)', max_length=50)
class SubCategory(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_subcategory')
vendor = models.ForeignKey(Vendors, on_delete=models.CASCADE, related_name='vendor_subcategory')
class ItemGroup(models.Model):
name = models.CharField('name', max_length=50, unique=True, blank=True)
class Item(models.Model):
subcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE, related_name='subcategory_item')
itemgroup = models.ForeignKey(ItemGroup, on_delete=models.CASCADE, related_name='itemgroup_item')
name = models.CharField('name', max_length=255)
I am trying to fetch all the subcategories using fields itemgroup and pincode from models Item and Itemgroup.
Here is my code:
SubCategory.objects.filter(vendor__pincode__pincode=500071).prefetch_related(Prefetch('subcategory_item',
queryset=Item.objects.filter(itemgroup__name='Biryanis')
))
Here is i am getting all the items in the subcategory model. But i want only those subcategories whose itemgroup='Biryanis' and pincode='500071'.
I think you are misunderstanding select_related and prefetch_related. These two methods are used only to gain performance by minimizing database calls.
Your code does not perform filter on the subcategory_item. Use the following code to do so.
SubCategory.objects.filter(vendor__pincode__pincode=500071).filter(subcategory_item__itemgroup__name='Biryanis')
If your question was about performance:
Using select_related and prefetch_related will not benefit you if you are calling the database once. And there are there some disadvantages in using those methods. Make sure you read the QuerySet docs.

Product order/purchase model in Django

I have a product model with name, description, currency, price, vendor and image fields, and I'm trying to implement ordering items, and I'm having a bit of trouble doing that.
Basically, what I want is to be able to access an Orders model in the admin and add an order number, customer name (I have already implemented these two), and some products with each product having a quantity.
# models.py
from django.db import models
class Vendor(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Product(models.Model):
currencies = [
('$', "US Dollars ($)"),
]
name = models.CharField(max_length=40)
description = models.TextField()
currency = models.CharField(max_length=5, choices=currencies, default="$")
price = models.DecimalField(max_digits=10, decimal_places=2)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
image = models.ImageField(default="not_found.jpg")
def __str__(self):
return self.name
class Customer(models.Model):
name = models.CharField(max_length=30)
date_of_birth = models.DateField()
def __str__(self):
return self.name
class Order(models.Model):
order_number = models.CharField(max_length=20)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
My attempts/solutions:
Adding ManyToManyField to Product (No Quantity)
Creating ProductInstance class with fk to product and order (Quantity added but You have to visit 2 different pages in the admin, and you can't see the items in orders page of admin)
Are there any other ways I can implement this or am I stuck with the second solution? It wouldn't be awful to do this but I rather avoid it and have the ability to add items on the orders page
I'm sorry if I sound like a beggar. I'm really not but I can't form nice-sounding sentences
Edit: I found what I needed!
Using the second solution I mentioned, I created a class called ProductInstance, and later renamed it to OrderProduct, made the following fields:
ForeignKey to Products
ForeignKey to Orders
IntegerField for quantity
The order class had the following fields:
CharField for order number
ForeignKey for customer
ManyToMany to product through OrderProduct
Then, I added the following in admin.py:
# admin.py
...
class OrderInlines(admin.TabularInline):
model = OrderProduct
fk_name = "order"
extra = 1
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
fields = ('order_number', "customer",)
inlines = (OrderInlines,)

How to make Django ORM query database through reverse ForeignKey work faster?

I have 3 models connected with ForeignKey:
class Product(TimeStampedModel):
product_id = models.AutoField(primary_key=True, )
shop = models.ForeignKey('Shop', related_name='products', to_field='shop_name', on_delete=models.CASCADE)
brand = models.ForeignKey('Brand', related_name='products', to_field='brand_name', on_delete=models.CASCADE)
class Meta:
indexes = [
models.Index(fields=['title', 'shop', 'sale']),
models.Index(fields=['shop', 'brand', 'price', 'title']), ]
class Brand(models.Model):
brand_id = models.AutoField(primary_key=True,)
brand_name = models.CharField(max_length=50, unique=True, blank=False, null=False)
class Shop(models.Model):
shop_id = models.AutoField(primary_key=True,)
shop_name = models.CharField(max_length=30, unique=True, blank=False, null=False, db_index=True)
From my view I try to filter Brands where available for this Shop, accessing Shop via Product ForeignKey:
brands = Brand.objects.filter(products__shop__shop_name=shop).distinct('brand_name').order_by('brand_name')
The problem is that this query takes a long time to process: from 1-3+ seconds. Is there a way to make it work faster?
May be I can add some Indexes? I have already tried some combinations (you can find them in Product - Meta class), but it seems like that doesn't help.
select_related('product') - throws an error: Invalid field name(s) given in select_related: 'product'. Choices are: (none)
Or may be there is a better way when I create a Brand entry - add a some kind available_in_shops = ListField(...)(I have found this can be made with JSONField, but I don't know yet how this works exactly)? And store there a list of shops where that Brand is available?

Models in Python Django not working for Many to Many relationships

I am trying to create the proper Django model that could fit the following reqs:
Person Class has 1 to many relations with the Address Class
Person Class has many to many relations with the Group Class
Book Class contains the collections of the Persons and the Groups
This is my code:
class Person(models.Model):
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=20)
def __str__(self):
return self.first_name+ ' - ' + self.last_name
class Address(models.Model):
person = models.ForeignKey(Person)
address_line = models.CharField(max_length=200)
def __str__(self):
return self.address_line
class Group(models.Model):
group_name = models.CharField(max_length=12)
persons = models.ManyToManyField(Person)
def __str__(self):
return self.group_name
class Book(models.Model):
record_name = models.CharField(max_length=12)
person = models.ForeignKey(Person )
group = models.ForeignKey(Group )
def __str__(self):
return self.record_name
However it's not correct:
1) A Group can now contain multiple Persons but the Persons do not contain any Group.
I am not sure if I should add to the Person class the following code:
groups = models.ManyToManyField(Group)
2) The Book class now contains only 1 record of Person & Group per Book record.
3) When I added the Foreign Keys to the models, I removed
on_delete tag:
person = models.ForeignKey(Person, on_delete=models.CASCADE())
because it does not compile it, asking for some params.
I know how to make all this for C#, but I am a kinda stucked with this simple task in Python/Django.
1) The ManyToMany field should appear only in one of the models, and by looks of things you probably want it in the Person model.
Its important to understand that the data about the ManyToMany field is saved in a differant table. Django only allows this field to be visable through buth models (so basiclly, choose where it is move convinient).
2)By the look of your structure I will suggest you use a ManyToMany field through a different table. here is an example:
class Activity(models.Model):
name = models.CharField(max_length=140)
description = models.TextField(blank=True, null=True)
class Route(models.Model):
title = models.CharField(max_length=140)
description = models.TextField()
activities_meta = models.ManyToManyField(Activity, through = 'RouteOrdering')
class RouteOrdering(models.Model):
route = models.ForeignKey(Route, on_delete=models.CASCADE)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='activita')
day = models.IntegerField()
order = models.IntegerField(default=0)
that way the data is binded to the ManyToMany field

Categories