I have these tables in a django app:
class Order(models.Model):
...
class SubOrder1(models.Model):
order = models.ForeignKey(Order, blank=True, null=True)
class SubOrder2(models.Model):
order = models.ForeignKey(Order, blank=True, null=True)
...
How can I write a query on Order which results only the orders which has at least one related SubOrder1 or SubOrder2? I need something like
Order.objects.filter(suborder__count__ge = 1, ...)
I am using Django = 1.9.2 and Python = 3.4.1
Use isnull field lookup:
orders_with_suborders = Order.objects.filter(
Q(suborder1__isnull=False) | Q(suborder2__isnull=False)
)
Annotate your queryset with the counts of the related models:
from django.db.models import Count
queryset = Order.objects.annotate(
num_suborder1=Count('suborder1', distinct=True),
num_suborder2=Count('suborder2', distinct=True),
)
See the docs about combining multiple aggregations to explain why we need distinct=True
Then you can use Q to filter objects where either of the counts is at least 1.
orders_with_suborders = queryset.filter(
Q(num_suborder1__gte=1) | Q(num_suborder1=1__gte=1),
)
A solution i just found would be something like:
Order.objects.filter(suborder1__id__gt = -1)
and i could use the same for SubOrder2. This is a solution, but not really djangonic. Is there any better solution?
You can get to the SubOrder1 from Order.
order = Order.objects.get(pk=pk)
suborders1 = order.suborder1_set.all()
Then you can iterate through the suborders:
for suborder in suborders1:
print (suborder)
Hope it help you
Related
I aim to create a dataframe of the Top 3 Selling menu_items in my Purchases table. My thoughts are to create a join on the Purchases model with the Menu_Item model where Purchases.menu_item = Menu_Item.title. I will convert the QuerySet to a DataFrame using django_pandas.io. I plan to use the sum of Menu_Item.price associated with each distinct Purchases.menu_item to determine the Top 3 menu_items of all the records in the Purchases table.
My problem is that I cannot join the two tables successfully. I’ve scoured the interwebz for a working solution to join two models with different field names, which returns all instances, and I tried various solutions, but the scarce articles on this topic yielded no joy.
models.py
...
class MenuItem(models.Model):
title = models.CharField(max_length=100, unique=True,
verbose_name="Item Name")
price = models.FloatField(default=0.00, verbose_name="Price")
description = models.CharField(max_length=500,
verbose_name="Item Description")
def __str__(self):
return f"title={self.title}; price={self.price}"
def get_absolute_url(self):
return "/menu"
def available(self):
return all(X.enough() for X in self.reciperequirement_set.all())
class Meta:
ordering = ["title"]
class Purchase(models.Model):
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE,
verbose_name="Menu Item")
timestamp = models.DateTimeField(auto_now_add=True,
verbose_name="DateTime")
def __str__(self):
return f"menu_item=[{self.menu_item.__str__()}]; time={self.timestamp}"
def get_absolute_url(self):
return "/purchases"
class Meta:
ordering = ["menu_item"]
I tried adapting too many unsuccessful code fragments to reproduce here, so I am looking at starting with a clean slate. I'm hoping you have an effective solution to share. Your help is greatly appreciated. Thanks.
You didn't mention what you have tried, so it is hard for me (and other developers) to give precise suggestions.
Anyway, have you tried something like
purchases = Purchase.objects.values(
'timestamp',
item_title=F('menu_item__title'),
item_price=F('menu_item__price'),
item_desc=F('menu_item__description'))
This queryset will fetch all values in one sql connection.
I'm working on my Django project and I'm triying to order my posts by the sum of 2 related models.
So this query should take the attendance count from the Post model and the attendant count from the Attending model and get the total sum.
These are the models:
class Post(models.Model):
title = models.CharField(max_length=100)
attendance = models.ManyToManyField(User, related_name='user_event_attendance')
class Attending(models.Model):
attendant = models.ForeignKey(User, related_name='events_attending', on_delete=models.CASCADE, null=True)
post = models.ForeignKey('Post', on_delete=models.CASCADE, null=True)
By now I have the following code but is not working properly:
views.py
new_query = Post.objects.filter(
Q(status='NOT STARTED', post_options='PUBLIC') | Q(status='IN PROGRESS',post_options='PUBLIC')).distinct().annotate(total_attendance=Count('attendance')).annotate(total_attendant=Count("attending__attendant")).annotate(total=F("total_attendant") + F("total_attendance")).order_by('-total')
You are getting duplicates in your counts, because of this documented behaviour:
Combining multiple aggregations with annotate() will yield the wrong results because joins are used instead of subqueries.
... For most aggregates, there is no way to avoid this problem, however, the Count aggregate has a distinct parameter that may help.
You can resolve this by adding the distinct parameter to both your count annotations:
new_query = Post.objects.filter(
Q(status='NOT STARTED', post_options='PUBLIC') | Q(status='IN PROGRESS',post_options='PUBLIC')
).distinct().annotate(
total_attendance=Count('attendance', distinct=True), # Add distinct
total_attendant=Count("attending__attendant", distinct=True) # Add distinct
).annotate(
total=F("total_attendant") + F("total_attendance")
).order_by('-total')
Also, Count("attending__attendant", distinct=True) can be simplified to just Count("attending", distinct=True), since there can only ever be one attendant for each Attending instance.
Is it possible to set the choices of a field from another table?
for example
class Initial_Exam(models.Model):
Question_category = models.CharField(max_length=20, choices = Job.Job_Position)
class Job(models.Model):
Job_Position = models.CharField(max_length=30, null=True)
something like that
To close this:
As commented above, instead of twisting my implementation, setting the foreign key for Initial_Exam and using __unicode__ on Job did the job
should look like this:
class Job(models.Model):
Job_Position = models.CharField(max_length=30, null=True)
def __unicode__(self):
return self.Job_Requirements
that would display the Job_Position as choices in the admin panel
I thank the community, really appreciate it
You can definitely tie to another model with a ForeignKey relationship, but if you've got a smaller number of choices, here's a pattern you might want to consider for smaller choice lists (I use it for fairly constant choice lists less than 10):
class FrequencyType(models.Model):
FREQ_MONTHLY = 1
FREQ_QUARTERLY = 3
FREQ_YEARLY = 12
FREQ_CHOICES = (
(FREQ_MONTHLY, 'Monthly'),
(FREQ_QUARTERLY, 'Quarterly'),
(FREQ_YEARLY, 'Yearly'),
)
frequency = models.SmallIntegerField(default=FREQ_MONTHLY, choices=FREQ_CHOICES)
or, another example:
class YesNoModel(models.Model):
NO = 0
YES = 1
YESNO_CHOICES = (
(NO, 'No'),
(YES, 'Yes'),
)
weight = models.IntegerField(default=NO, choices=YESNO_CHOICES)
Good luck.
I would like to order by entry_count but it seems (from the django error) I can only order by name and status. How can I order by entry_count in this example? Thanks
Category.objects.filter(status='Published').order_by('-entry_count')
Model.py
class Category(models.Model):
"""
Entry Categories.
"""
name = models.CharField(max_length=60, help_text="Title of Category")
status = models.CharField(max_length=16, choices=STATUS_CHOICES,
default="Draft", )
#property
def entry_count(self):
return Entry.objects.filter(category=self.id).count()
You can do this by using aggregation:
from django.db.models import Count
Category.objects.annotate(
entry_count=Count('entry_set')
).order_by('-entry_count')
Like this, you'll get all the counts in one query and all the category objects will have entry_count, so you can remove the #property from the model.
I have the following self referencing model that gives who this profile supports.
supports = models.ManyToManyField('self', blank=True, symmetrical=False,
related_name='supporters')
And I want the count not supports, supporters that support this user.
Any ideas ?
def get_queryset(self):
qs = super(ProfileListView, self).get_queryset()
if self.request.GET.get('s'):
sorting = self.request.GET.get('s')
if sorting == 'pop':
qs = ......
return qs
I will assume I have an instance of your model with the name myUser:
supporters = myUser.supports_set.all()
Annotate number of supporters like below, solved my problem
qs = qs.annotate(number_of_supporters=Count('supporters'))
qs = qs.order_by('-number_of_supporters')