Django join multiple models using django ORM - python

I googled and read many articles but got confused in multiple table join.
My models looks like-
class ProductCategory(models.Model):
category_name = models.CharField(max_length=200,blank=True, null=True, unique=True)
category_image = models.ImageField(upload_to='category', null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
status = models.CharField(max_length=10, default='Active', choices=status)
def __unicode__(self):
return '%s' % ( self.category_name)
class ProductSubCategory(models.Model):
category = models.ForeignKey(ProductCategory)
sub_category_name = models.CharField(max_length=200,blank=True, null=True, unique=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
sub_category_image = models.ImageField(upload_to='subcategory', null=True, blank=True)
status = models.CharField(max_length=10, default='Active', choices=status)
def __unicode__(self):
return '%s' % ( self.sub_category_name)
class Product(models.Model):
category = models.ForeignKey(ProductCategory)
sub_category = models.ForeignKey(ProductSubCategory)
product_name = models.CharField(max_length=200,blank=True, null=True)
product_price = models.FloatField(default=0)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
# is_discountable = models.CharField(max_length=3, default='Yes', choices=option)
status = models.CharField(max_length=10, default='Active', choices=status)
def __unicode__(self):
return '%s' % ( self.product_name)
class ProductColor(models.Model):
product = models.ForeignKey(Product)
product_color = models.ForeignKey(Color, related_name='product_color_id', blank=True, null=True)
product_size = models.ForeignKey(Size, related_name='product_size_id', blank=True, null=True)
class ProductImages(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)
product_image = models.ImageField(upload_to='images', null=True, blank=True)
Now in views, I want to get the product filters according to category and sub-category having all the images and colors. Query is something like-
SELECT product.*, productcolor.*, productimage.* FROM product
LEFT JOIN productcolor ON productcolor.product_id = product.id
LEFT JOIN productcolor.product_id = product.id
LEFT JOIN productimage ON productimage.product_id = product.id
WHERE product.category_id=1 and product.sub_category_id=1

Accordingly to your SQL, this will do.
Product.objects.filter(category=<category>, sub_category=<sub_category>) \
.prefetch_related('productcolor_set', 'productimages_set')
This query will prefetch all (with .prefetch_related()) ProductColor and ProductImages related to Product that have your <category> and <sub_category>, they would be stored in productcolor_set and productimages_set respectively.
Also i would suggest to rename your ProductImages model to ProductImage because it represents only one product image.

ProductCategory.productsubcategory_set.all()

Related

Django - Getting an object from an object

I'm trying to get the object "Book" from prommotion. Book is a ForeignKey in "prommotion", and I filtered all the prommotions that are active. I need to get the "Book" object from the Prommotion if its active and return it.
(And I know promotion is spelled wrong)
Views:
class Book_PrommotionViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Prommotion.objects.filter(active=True)
serializer = PrommotionSerializer(queryset, many=True)
return Response(serializer.data, HTTP_200_OK)
Prommotion Model:
class Prommotion(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
precent = models.DecimalField(decimal_places=2, max_digits=255, null=True, blank=True)
active = models.BooleanField(default=False)
date_from = models.DateField()
date_to = models.DateField()
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'Prommotion'
verbose_name_plural = 'Prommotions'
Book Model:
class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=255, null=True, blank=True)
author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True, blank=True)
price = models.DecimalField(decimal_places=2, max_digits=255)
published = models.DateField()
edition = models.CharField(max_length=255)
isbn_code = models.CharField(max_length=255)
pages = models.IntegerField(blank=True, null=True, default=0)
description = models.TextField(null=True, blank=True)
cover = models.CharField(max_length=30, choices=Cover.choices(), default=None, null=True, blank=True)
genre = models.CharField(max_length=30, choices=Genre.choices(), default=None, null=True, blank=True)
language = models.CharField(max_length=30, choices=Language.choices(), default=None, null=True, blank=True)
format = models.CharField(max_length=30, choices=Format.choices(), default=None, null=True, blank=True)
publisher = models.CharField(max_length=30, choices=Publisher.choices(), default=None, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Book'
verbose_name_plural = 'Books'
The first way to get all Books that are related to your active promotions is to extract the book ids from the queryset and pass it to a Book filter
active_promotions = Prommotion.objects.filter(active=True)
Book.objects.filter(id__in=active_promotions.values('book_id'))
Or simply filter books with active promotions by using the double underscore syntax to follow relationships
Book.objects.filter(prommotion__active=True).distinct()

How to access other model fields through foreign key in Django Views

I want to query from OrderItem Model like
total_orders = OrderItem.objects.filter(product.user == request.user.id).count()
but i am getting error
**
NameError at /home
name 'product' is not defined
**
MY MODELS:
Product Model:
class Product(models.Model):
title = models.CharField(max_length=150)
user = models.ForeignKey(
User, blank=True, null=True, on_delete=models.SET_DEFAULT, default=None)
description = models.TextField()
price = models.FloatField()
quantity = models.IntegerField(default=False, null=True, blank=False)
minorder = models.CharField(
max_length=150, help_text='Minum Products that want to sell on per order', null=True, default=None, blank=True)
image = models.ImageField()
category = models.ForeignKey(
Categories, default=1, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
def __str__(self):
return self.title
Order Item Model
class OrderItem(models.Model):
product = models.ForeignKey(
Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(
Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.FloatField(default=0, null=True, blank=True)
date_orderd = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
price = models.FloatField(blank=True, null=True)
def __str__(self):
return str(self.product)
My View:
def home(request):
total_orders = OrderItem.objects.filter(
product.user == request.user.id).count()
return render(request, "sellerprofile/home.html", {'total_orders': total_orders})
Do:
total_orders = OrderItem.objects.filter(product__user=request.user).count()
You can look at the documentation here about field lookups on more detail.

Accessing a parent's model attributes from child model in django

please can anyone help me out am stuck i want to access items in the item model which i have referenced in the OrderItem model but am trying to access the item from Order model
here are the models
here is the model that am using to access
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
ref_code = models.CharField(max_length=20)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
order_date = models.DateTimeField()
ordered = models.BooleanField(default=False)
shipping_address = models.ForeignKey('Address',on_delete=models.SET_NULL,related_name='shipping_address',blank=True,null=True)
payment = models.ForeignKey('Payment',on_delete=models.SET_NULL,blank=True,null=True)
being_delivered = models.BooleanField(default=False)
received = models.BooleanField(default=False)
refund_requested = models.BooleanField(default=False)
refund_granted = models.BooleanField(default=False)
Here is the parent model which i want to access
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
ordered_order = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
and the item am trying to access must in this model
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.IntegerField()
discount_price = models.IntegerField(blank=True, null=True)
category = models.ForeignKey(Categories, on_delete=models.DO_NOTHING)
tags = models.ManyToManyField(Tags, related_name='itemTags')
slug = models.SlugField(max_length=200, unique=True)
size = models.CharField(blank=True, null=True, max_length=5)
model = models.CharField(max_length=100, blank=True, null=True)
description = models.TextField()
quantity = models.IntegerField(default=1)
image = models.ImageField()
color = models.CharField(max_length=100, blank=True, null=True)
brand = models.CharField(max_length=100, blank=True, null=True)
Display = models.DecimalField(max_digits=100,
decimal_places=1,
blank=True,
null=True)
ram = models.CharField(max_length=100, blank=True, null=True)
material = models.CharField(max_length=100, blank=True, null=True)
hdd = models.CharField(max_length=100, blank=True, null=True)
size = models.CharField(max_length=100, blank=True, null=True)
lens = models.CharField(max_length=100, blank=True, null=True)
created_at = models.DateField(auto_now_add=True)
i was trying with this but seem not to work
recent_orders=Order.objects.filter(user=2)
for item in recent_orders:
print(item.items.item.title)
can anyone help me out Please!!!
You need thi code:
recent_orders=Order.objects.filter(user=2)
for order in recent_orders:
for order_item in order.items:
print(order_item.item.title)
try to give different names to all your variables, this will make programming more effective

Pk fields always ends up in resulting query GROUP BY clause

I have my model hierarchy defined as follows:
class Meal(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
discount_price = models.DecimalField(blank=False, null=False, decimal_places=2, max_digits=4)
normal_price = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=4)
available_count = models.IntegerField(blank=False, null=False)
name = models.CharField(blank=False, null=False, max_length=255)
active = models.BooleanField(blank=False, null=False, default=True)
class Order(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
number = models.CharField(max_length=64, blank=True, null=True)
buyer_phone = models.CharField(max_length=32, blank=False, null=False)
buyer_email = models.CharField(max_length=64, blank=False, null=False)
pickup_time = models.DateTimeField(blank=False, null=False)
taken = models.BooleanField(blank=False, null=False, default=False)
class OrderItem(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
amount = models.IntegerField(blank=False, null=False, default=1)
I'm trying to get some statistics about orders and I came up with django orm call that looks like this:
queryset.filter(created_at__range=[date_start, date_end])\
.annotate(price=Sum(F('items__meal__discount_price') * F('items__amount'), output_field=DecimalField()))
.annotate(created_at_date=TruncDate('created_at'))\
.annotate(amount=Sum('items__amount'))\
.values('created_at_date', 'price', 'amount')
The above however doesn't give me the expected results, because for some reason the id column still ends up in the GROUP BY clause of sql query. Any help with that?
To make it work I had to do the following:
qs.filter(created_at__range=[date_start, date_end])\
.annotate(created_at_date=TruncDate('created_at'))\
.values('created_at_date')\
.annotate(price=Sum(F('items__meal__discount_price') * F('items__amount'),
output_field=DecimalField()))
.annotate(amount=Sum('items__amount'))
Which kind of makes sense - I pull only the created_at field, transform it and then annotate the result with two other fields.

Django model query

I have question about Django query models. I know how to write simple query, but Im not familiar with LEFT JOIN on two tables. So can you give me some advice on his query for better understanding DJango ORM.
query
select
count(ips.category_id_id) as how_many,
ic.name
from
izibizi_category ic
left join
izibizi_product_service ips
on
ips.category_id_id = ic.id
where ic.type_id_id = 1
group by ic.name, ips.category_id_id
From this query I get results:
How many | name
0;"fghjjh"
0;"Papir"
0;"asdasdas"
0;"hhhh"
0;"Boljka"
0;"ako"
0;"asd"
0;"Čokoladne pahuljice"
0;"Mobitel"
2;"Čokolada"
And I have also try with his Django query:
a = Category.objects.all().annotate(Count('id__category',distinct=True)).filter(type_id=1)
But no results.
My models:
models.py
class Category(models.Model):
id = models.AutoField(primary_key=True)
type_id = models.ForeignKey('CategoryType')
name = models.CharField(max_length=255)
def __str__(self):
return str(self.name)
class Product_service(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=True, null=True)
selling_price = models.DecimalField(decimal_places=5, max_digits=255, blank=True, null=True)
purchase_price = models.DecimalField(decimal_places=5, max_digits=255, blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
image = models.FileField(upload_to="/", blank=True, null=True)
product_code = models.CharField(max_length=255, blank=True, null=True)
product_code_supplier = models.CharField(max_length=255, blank=True, null=True)
product_code_buyer = models.CharField(max_length=255, blank=True, null=True)
min_unit_state = models.CharField(max_length=255, blank=True, null=True)
state = models.CharField(max_length=255, blank=True, null=True)
vat_id = models.ForeignKey('VatRate')
unit_id = models.ForeignKey('Units')
category_id = models.ForeignKey('Category')
If you culd help me on this problem.
You should add a related name on the category_id field like:
category_id = models.ForeignKey('Category', related_name="product_services")
so that in your query you can do:
a = Category.objects.all().annotate(Count('product_services',distinct=True)).filter(type_id=1)
and then you can access the individual counts as:
a[0].product_services__count

Categories