0
select *
from sample
join process
on sample.processid = process.id
where (processid) in (
    select max(processid) as processid
    from main_sample
    group by serialnumber
) 
ORDER BY sample.create_at desc;

models.py

class Sample(models.Model):
    processid = models.IntegerField(default=0) 
    serialnumber = models.CharField(max_length=256)  ##
    create_at = models.DateTimeField(null=True)

class Process(models.Model):
    sample = models.ForeignKey(Sample, blank=False, null=True, on_delete=models.SET_NULL)

Hi I have two models and I need to change this SQL query to Django ORM, Python code.

I need to retrieve the latest Sample(by processid) per unique serial number.

for example,

enter image description here

=> after RUN query

enter image description here

How can I change the SQL query to ORM code? how can i change the subquery to ORM?

Thanks for reading.

2
  • 1
    Can you explain exactly what you want as a result and share your models? It looks like you want to retrieve the latest Sample (by processid) per unique serialnumber? Do you need the full result(s) or just some individual values/columns? Commented Mar 11, 2022 at 4:31
  • Thanks! I need to retrieve the latest Sample(by processid) per unique serial number!! I added the example. Commented Mar 11, 2022 at 4:54

2 Answers 2

1

EDIT: To also order by a column that is not one of the distinct or retrieved columns you can fall-back on subqueries. To filter by a single row from a subquery you can use the syntax described in the docs here

from django.db.models import Subquery, OuterRef
subquery = Subquery(Sample.objects.filter(
    serialnumber=OuterRef('serialnumber')
).order_by(
    '-processid'
).values(
    'processid'
)[:1])
results = Sample.objects.filter(
    processid=subquery
).order_by(
    'create_at'
)

When using PostgreSQL you can pass fields to distinct to get a single result per a certain column, this returns the first result so combined with ordering will do what you need

Sample.objects.order_by('serialnumber', '-processid').distinct('serialnumber')

If you don't use PostgreSQL. Use a values query of the column that should be unique and then annotate the queryset with the condition that should group the values, Max in this case

from django.db.models import Max
Sample.objects.order_by(
    'serialnumber'
).values(
    'serialnumber'
).annotate(
    max_processid=Max('processid')
)
Sign up to request clarification or add additional context in comments.

4 Comments

Really thanks for replying! I tried your code so I can get the filtered result ! but how can i get the sorted elements by 'create_at' ?? I missed the question for the sorting field. If I add the order_by('create_at') option after the ORM, it returns all the Sample elements, not filtered elements...
and can I ask that if i can get the other fields (create_date etc)? this ORM can only get 'serial_number' and max process id.
@Shale Added an update to the answer at the top, using a subquery what you want should be possible. The update should get you the actual model instances/rows instead of just values which I think is what you want
Really really really thanks! you saved my life !!!! @Iain
0

I think this is what you need:

  1. If want multiple related objects
samples = Sample.objects.prefetch_related('process').group_by('serialinumber')
  1. If you want related objects for only one object
samples = Sample.objects.filter(id=1).select_related('process').group_by('serialinumber')

2 Comments

Thanks for replying! But How can i change the subquery (where (processid) in ( select max(processid) ... ) ) to ORM? I need the MAX processid by each serialnumber
Need to write another query on first query: say samples.objects.latest(process__id) latest will give the last process__id

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.