Get the latest instance of a foreign key in django models - django

Hi I am facing difficulty with a query in Django ORM:
I have two models:
class Student(models.Model):
name = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class choices:
CHOICES = {(0, "Present"),(1, "Absent")}
class Attendance(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE,
related_name='attendance')
date = models.DateField()
state = models.PositiveSmallIntegerField(choices=choices.CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
I want to get all the students who were present on their respective latest dates of attendance.

I have a solution that requires three separate database queries
First get the latest Attendance id for each student and get the latest Attendance id where the status is present.
latest_attendances = Attendance.objects.order_by('student', '-date').distinct('student').values_list('id', flat=True)
latest_present_attendances = latest_attendances.filter(state=0)
Using set arithmetic we can get all the Attendance ids that are common to both (latest and "present")
set(latest_attendances) & set(latest_present_attendances)
Then pass it to a Student query
Student.objects.filter(attendance__in=set(latest_attendances) & set(latest_present_attendances))

Related

How to inner join tables based on ManyToManyField and group by a parameter and get latest one in Django?

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'))

Querying ManyToManyTable In Django

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.

Django - Query : Annotate Queryset with Related Model fields

I have following Schema in Django with PostgreSQL.
Class Person (models.Model):
name = models.CharField(max_length=255)
email= models.CharField(max_legth = 255)
created_at = models.DateTimeField()
Class PersonTask(models.Model):
person = models.ForeignKey(Person)
title = models.TextField()
created_at = models.DateTimeField()
Class PersonHistory(models.Model):
person = models.ForeignKey(Person)
note = models.TextField()
created_at = models.DateTimeField()
Now I need to query the DB like all values of Person with latest PersonTask__title as max_task and latest PersonHistory__note as max_note
Eg:
<Queryset: [
{name: "abc" ,email:"abc#gmail.com",created_at :"2019-01-02", max_task:"This is my latest tasktitle" , max_note: "This is my latest history note"},
{name: "abcd" ,email:"abcd#gmail.com",created_at :"2019-03-02", max_task:"This is my latest tasktitle for abcd" , max_note: "This is my latest history note for abcd"}
]>
But, I could max get is either id of Latest Task and Latest History by
Person.objects.filter(customer_id= 1).\
annotate( max_task = Max('persontask')).\
annotate(max_note = Max('personhistory')).\
order_by('-id')
Or a random task or note texts using below query
Person.objects.filter(customer_id= 1).\
annotate( max_task = Max('persontask__title')).\
annotate(max_note = Max('personhistory__note')).\
order_by('-id')
How this can be tackled??
As you did not mention the ForeignKeys between these models, I suspect that Task and History have FK to Person in field named person.
I would use Subquery with combination of OuterRef to tackle this query
from django.db.models import OuterRef, Subquery
result = (
Person.objects
.filter(customer_id=1)
.annotate(
task_title=Subquery(Task.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('title')[:1]),
history_note=Subquery(HistoryNote.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('note')[:1])
)
.order_by('-id')
)
If tasks and history are related with person you need a relationship between your models.
something like this.
class PersonTask(models.Model):
person = models.ForeignKey(Person, related_name="tasks", on_delete=models.CASCADE)
title = models.TextField()
created_at = models.DateTimeField()
class PersonHistory(models.Model):
person = models.ForeignKey(Person, related_name="histories", on_delete=models.CASCADE)
note = models.TextField()
created_at = models.DateTimeField()
And then you could get last task and last history:
person = Person.objects.get(name="name")
person.tasks.last()
person.histories.last()

How to fetch translation record in django

I am new in django framework.I have 3 tables in mysql database. I want to fetch data from main table with translation table and images table.
My model.py
class Country(models.Model):
#id = models.IntegerField(primary_key=True)
iso_code = models.CharField(max_length=2, unique=True)
slug = models.CharField(max_length=255, unique=True)
is_featured = models.IntegerField(max_length=1)
class Meta:
db_table = 'rh_countries'
class CountryTranslation(models.Model):
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
locale = models.CharField(max_length=2)
class Meta:
db_table = 'rh_countries_translations'
class CountryImage(models.Model):
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
image = models.CharField(max_length=255)
is_main = models.IntegerField(max_length=1)
class Meta:
db_table = 'rh_country_images'
Now I want to fetch all country with translation record by locale and associated image.
Please give a solution if anyone know.
You can do this by using a filtering, and annotate:
from django.db.models import F
Country.objects.filter(
countrytranslation__locale=mylocale
).annotate(
name=F('countrytranslation__name')
)
This will result in a QuerySet with all Countrys (that have a Translation for the given mylocale). These Countrys will have an extra attribute .name that is the translated name of the Country.
So given the translations exist, then for mylocale='en', this will result in a QuerySet, with Country(name='Germany', iso_code='de'), and for mylocale='de', it will result in Country(name='Deutschland', iso_code='de') (here this is a bit an ad hoc format, to demonstrate how it works).
Note: ForeignKeys typically do not end with _id. Django will automatically add an _id suffix to the database column. The foreign key itself is on the Python/Django level represented as a lazy loaded attribute.

django - Filter foreign key in a queryset

In the following model:
class Product(models.Model):
name = models.CharField(max_length = 255)
created_in = models.DateTimeField(auto_now=True)
class Price(models.Model):
product = models.ForeignKey(Product)
price = models.DecimalField(max_digits=6, decimal_places=2)
created_in = models.DateTimeField(auto_now=True)
I want to do things like this:
products = Product.objects.filter(price__gte=Decimal(10)) #It considered all prices I just need the last one
How do i query a product considering only the last price "created_in" related?
Thanks!!
latest() is what you need:
Returns the latest object in the table, by date, using the field_name
provided as the date field.
products = Product.objects.filter(price__gte=Decimal(10)).latest('price__created_in')