Given the following model, I'm trying to generate a data set that will get the quantity field from OrderItems while also getting the other columns from Item and Order. I'm trying to write the query in Django's ORM but have been having issues.
class Order(models.Model):
items = models.ManyToManyField("Item", through="OrderItems")
order_date = models.DateTimeField()
class Item(models.Model):
name = models.CharField(max_length=250)
orders = models.ManyToManyField("Order", through="OrderItems")
class OrderItems(models.Model):
order = models.ForeignKey("Order", null=False, on_delete=models.CASCADE)
item = models.ForeignKey("Item", null=False, on_delete=models.CASCADE)
quantity = models.IntegerField()
The query I've tried:
Order.objects.prefetch_related('items').filter(id=order_id)
That will get me the Items for the order, but I can't figure out how to get the quantity field.
#William Thank you for your response - if you post it as the answer I'll tick it accordingly. I was missing that those objects are also available in prefetch_related.
Related
I have two models with ManyToManyField relationship:
class Education(models.Model):
title = models.CharField(default=None, max_length=100)
content = models.TextField(default=None)
price = models.ManyToManyField(Price)
class Price(models.Model):
cost = models.CharField(default=None, max_length=20)
created_at = models.DateTimeField(auto_now=True, null=True, blank=True)
I can fetch all rows like this:
result = Education.objects.filter(price__in=Price.objects.all()).select_related('Price')/
.values_list('title', 'content', 'price__cost', 'price__created_at')
But now i want to group by education.id and the cost parameter should be latest parameter that inserted(based on created_at).
So i want to have list of all Education with latest cost that inserted for every education.
Will it work for you, It will return the respective id
Education.objects.filter(price__in=Price.objects.all()).select_related('Price').values('id').annotate(price_id=Max('price__id'))
I am working on a photos project where a user can Download or Like a photo (do other operations as well) . I have two models to track this information. Below are the models used (Postgres the database used).
# Photo model stores photos
# download_count, like_count is stored in the same model as well for easier querying
class Photo(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
image = models.ForeignKey(Image, null=True, on_delete=models.CASCADE)
download_count = models.IntegerField(default=0)
like_count = models.IntegerField(default=0)
views = GenericRelation(
'Stat', related_name='photo_view',
related_query_name='photo_view', null=True, blank=True)
downloads = GenericRelation(
'Stat', related_name='photo_download',
related_query_name='photo_download', null=True, blank=True)
# Stat has generic relationship with photos. So that it can store any stats information
class Stat(models.Model):
VIEW = 'V'
DOWNLOAD = 'D'
LIKE = 'L'
STAT_TYPE = (
(VIEW, 'View'),
(DOWNLOAD, 'Download'),
(LIKE, 'Like'),
)
user = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL)
content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, default=0)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
stat_type = models.CharField(max_length=2, choices=STAT_TYPE, default=VIEW)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
My requirement is fetch the Photos that are popular this week. The popularity score should consider the likes count, download count.
I had written below query to get the popular photos this week which checks the likes or downloads created this week.
# week number
current_week = date.today().isocalendar()[1]
photos = Photo.objects.filter(Q(likes__created_at__week=current_week) | Q(downloads__created_at__week=current_week))\
.order_by('id', 'download_count', 'like_count')\
.distinct('id')
Problem: With the above query, the result set is always ordered by id even though other fields are mentioned.
Requirement: The photos should be ordered by sum of total likes and downloads so that they will be sorted by popularity.
Please suggest me a way to achieve this considering the database performance.
Thank You
You can use annotate() and F object for such cases:
photos = Photo.objects.filter().annotate(like_download=F('download_count') + F('like_count')).order_by('like_download').distinct()
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
The result above will be ordered by pub_date descending, then by headline ascending. The negative sign in front of "-pub_date" indicates descending order.
So if you give id, it will be ordered by id first.
You can use annotate in your case.
Per-object summaries can be generated using the annotate() clause. When an annotate() clause is specified, each object in the QuerySet will be annotated with the specified values.
Thanks to #biplove-lamichhane for suggesting me annotate function. I could able to achive the desired response by using the below query
photos = Photo.objects.filter(is_active=True)\
.filter(Q(likes__created_at__week=current_week) | Q(downloads__created_at__week=current_week))\
.annotate(score=F('download_count') + F('like_count'))\
.order_by('-score')\
.distinct()
I have two django models:
class Order(models.Model):
date = models.DateTimeField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='orders')
shipping_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=9)
comment = models.CharField(max_length=100, blank=True, null=True)
class OrderStatus(models.Model):
STATUS_ACCEPTED = 1
STATUS_PROCESSING = 2
STATUS_DELIVERING = 3
STATUS_COMPLETED = 4
CODE_CHOICES = (
(STATUS_ACCEPTED, 'accepted'),
(STATUS_PROCESSING, 'processing'),
(STATUS_DELIVERING, 'delivering'),
(STATUS_COMPLETED, 'completed'),
)
date_created = models.DateTimeField(auto_now_add=True)
code = models.PositiveSmallIntegerField(choices=CODE_CHOICES)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='status_list')
Normally if I wanted to get all the orders with 'accepted' status I could write Order.objects.filter(orderstatus__code=1).
But how can I make django admin to create OrderStatus list filter?
I have googled a lot and found only one answer here on stackoverflow, which claims simply adding reverse model ('orderstatus' in my case) to list_filter tuple should work, but I get an error message: The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
What am I doing wrong?
Did you try by you self before posting question here, because there are lots of question related to this one, Any way i think this link will help you.
https://books.agiliq.com/projects/django-admin-cookbook/en/latest/many_to_many.html
The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
This is because orderstatus is not a field in your model. Either change order field to orderstatus or change the name passed to list_filter to the name of your field.
I have for example a model like this:
class Transaction(models.Model):
amount = models.FloatField()
seller = models.ForeignKey(User, related_name='sells', on_delete=models.CASCADE)
buyer = models.ForeignKey(User, related_name='purchased', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
I want to group by all transactions seperated by each date and find some of them. If the created_at is of type DateField I could simply find the count on each day by this query:
Transaction.objects..values('created_at').annotate(count=Count('created_at_date')
But this doesn't work DateTimeFeilds.
My question is how can i find total count of transactions for each date for this model type.
The following will work for django 2.1 and above.
Transaction.objects.values('created_at__date').annotate(count=Count('id')).values('created_at__date', 'count').order_by('created_at__date')
You need to use __date after the name for lookup and need to put an order_by at the end.
Not sure about the previous django versions.
I am running a filter query in Django with range. I thought filter always returned a queryset that was grouped by the primary key, but it seems not.
These are my models:
class MCode(models.Model):
code = models.CharField(max_length=16)
class Product(models.Model):
id = models.CharField(max_length=40, primary_key=True, db_index=True)
mcode = models.ForeignKey(MCode, null=True, blank=True, db_index=True)
class Review(models.Model):
review_id = models.CharField(max_length=32, primary_key=True, db_index=True)
product = models.ForeignKey(Product, db_index=True)
rating = models.IntegerField()
time = models.DateTimeField(db_index=True)
And this is my code:
mcode = 'M83'
base = Product.objects
tcode_obj = MCode.objects.filter(code=mcode.upper())
return base.filter(tcode=tcode_obj,
review__time__range=[date_from, date_to])
I'm getting five results, but three of them have the same primary key. It looks like I'm getting a result for each review, not each product.
Does anyone know how could I group these products by ID, and annotate with the count of the attached reviews?
When you select based on something that could match multiple times, such as Product with Reviews during a range of time, each match is added to the queryset, even if it's a duplicate of an item already there. There's actually times where you might want this behavior, but if you need to limit the queryset to just unique items, use .distinct() at the end of your query. Getting duplicates is also common when using logical ORs in your query, so be aware of times you do that and remember to use .distinct() there as well.