Order queryset using the number of related objects in Django - django

Let's say I have the following in models.py:
class A(models.Model):
...
class B(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
What I want to do is sort a queryset for A based on how many B objects they have, in descending order. What is the best approach to this issue? Thanks for any help.

You can work with a .annotate(…) [Django-doc] and then .order_by(…) [Django-doc]:
from django.db.models import Count
A.objects.annotate(
nb=Count('b')
).order_by('-nb')
Since django-3.2 you can work with .alias(…) [Django-doc] to prevent calculating this both as column and in the ORDER BY clause:
from django.db.models import A
A.objects.alias(
nb=Count('b')
).order_by('-nb')

This is:
queryset = A.objects.filter().order_by('B_A')
Here 'B_A' you have to put the related name
class A(models.Model):
...
class B(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE, related_name = 'B_A')

Related

Ordering objects by calculating the sum of fields on a foreign key Django

Say I had some models defined as such:
Class Owner(models.Model):
pass
Class Item(models.Model):
value = models.IntegerField()
owners = models.ForeignKey(Owner, related_name="items")
How would I go about sorting Owners based off of the sum of the value of their items, ideally as a QuerySet that I could pass onto a template like Owner.objects.order_by('-valueofItems')
Use ORM aggregation together with order_by
from django.db.models import Sum
Owner.objects.annotate(total_value=Sum('item_value')).order_by('-total_value')

Reverse lookup in django

I have two models as follows
class IntakeDetails(models.Model):
intake = models.ForeignKey(intake, on_delete=models.CASCADE)
lecturer = models.ForeignKey(Lecturer, on_delete=models.CASCADE)
module= models.ForeignKey(Module, on_delete=models.CASCADE)
class AssignAssignment(models.Model):
title=models.CharField(max_length=30)
duedate=models.DateField()
intakedetails=models.OneToOneField(IntakeDetails, on_delete=models.CASCADE,related_name='details'
I have a queryset
queryset = IntakeDetails.objects.filter(lecturer=self.request.user.id)
it filters all the intakedetails that belong to that lecturer in that table. but i want it to filter that intakedetails that doesnt exist in assign assignment model.
anyone can help ?
Try the following based on the related_name details:
IntakeDetails.objects.filter(lecturer=lecturer_id,details__isnull=True)

django rest framework an always sorting field

I want to have a fixed sorting field applied to all custom sortings. To be more specific imagine we have a list of employees, if user choose this form be sorted by hire_date, I want the result be sorted by hire_date and employee_id together. I mean each ordering should be ordered by employee_id inside! For example if we have 5 employees hired today, if hire_date is the sorting field, these 5 be sorted by employee_id and for the other days the same story.
using the following is not the cure. It only sorts them on employee_id when no ordering is set:
queryset = models.Employee.objects.order_by('id')
And this one's result is same as previous:
filter_backends = (CustomFilterSetBackend, filters.OrderingFilter)
custom_filters = (
........
)
ordering_fields = (............)
ordering = ('id',)
tnx a million
In model add this:
class Employee(models.Model):
......
......
class Meta:
ordering = ['-hire_date','employee_id']
It will order by hire_date and if dates are same then employee_id.
Same problem i had got back while working so , there are few solutions you can adopt ,
In your Employee model class you can do these ,
from __future__ import unicode_literals
from django.db import models
class Employee(models.Model):
....
....
class Meta:
# Latest by hire_date ascending, employee_id ascending.
ordering = ['hire_date', 'employee_id']
And also you can do some thing like these at query end ,
from your_app.models import Employee
queryset = models.Employee.objects.order_by('employee_id')
Third solution can be combined form of first two solutions as i mentioned and as you described in comment that can be like ,
from __future__ import unicode_literals
from django.db import models
class Employee(models.Model):
....
....
class Meta:
# Latest by hire_date ascending, employee_id ascending.
ordering = ['employee_id']
Now when you fetch employee you should do these ,
(i am assuming these from views.py file)
from your_app.models import Employee
queryset = models.Employee.objects.order_by('hire_date')
Let me know if any problem in third approach.

Django, sum of fields in intermediary model with given queryset

I have 2 models, one of them has many to many relation with itself through other table like this.
class a(models.Model):
# fields
class b(models.Model):
from_a = models.ForeignKey(a)
to_a = models.ForeignKey(a)
count = models.PositiveIntegerField()
Now, what I wonder is, what is the best way of calculating sum of counts in b's where from_a is "something". This one seems trivial, but I can't figure it out.
from django.db.models import Sum
b.objects.filter(from_a__whatever='something').aggregate(Sum('count'))

Django filter query using hasattr (or something like it)

I want to perform a filter on a model and return all objects that have a specific attribute.
model.objects.filter(hasattr(model, 'attrname'))
This obviously doesn't work, but not sure how to efficiently implement something siilar.
Thanks
EDIT
An example of where I would use this is when a model is inherited from another
class model1(models.Model):
...
class model2(model1):
...
if I do a model1.objects.all() each of the returned objects that are in model2 will have an extra attribute
If the models are related, you can the isnull in the filter.
model1.objects.filter('related_name__field_name__isnull=False)
where related name is in for the foreign key in model2
For Example:
class Owner(models.Model):
user = models.CharField(max_length=10)
class Car(models.Model):
car_type = models.CharField(max_length=10)
owner = models.ForeignKey(Owner, related_name='cars',
on_delete=models.CASCADE)
For owners with cars:
owners = Owner.objects.filter(cars__id__isnull=False)
I just put it in a:
try:
....
except AttributeError:
....
The way I did it was to suppress the FieldError exception:
from django.core.exceptions import FieldError
from contextlib import suppress
with suppress(FieldError):
model.objects.filter(field_in_other_class=value)
hope that helps