2

I need to construct a query in Django, and I'm wondering if this is somehow possible (it may be really obvious but I'm missing it...).

I have a normal query Model.objects.filter(x=True)[:5] which can return results like this:

FirstName    LastName    Country
Bob           Jones        UK
Bill          Thompson     UK
David         Smith        USA

I need to only grab rows which are distinct based on the Country field, something like Model.objects.filter(x=True).distinct('Country')[:5] would be ideal but that's not possible with Django.

The rows I want the query to grab ultimately are:

FirstName    LastName    Country
Bob           Jones        UK
David         Smith        USA

I also need the query to use the same ordering as set in the model's Meta class (ie. I can't override the ordering in any way).

How would I go about doing this?

Thanks a lot.

4
  • I only need the top five rows from the DB. Commented Nov 23, 2009 at 17:36
  • This is a tough one but I'm not sure that I'm fully understanding the question. Do you want the top five rows in which the country is distinct? Commented Nov 23, 2009 at 17:53
  • 2
    @S.Lott, slicing a queryset does not turn it into a list. Dx143 is correct that this is the way to just get the top 5 elements from the database. Commented Nov 23, 2009 at 19:36
  • Looks like there's a ticket for this: code.djangoproject.com/ticket/6422 Commented Feb 4, 2010 at 20:38

4 Answers 4

4

I haven't tested this, but it seems to me a dict should do the job, although ordering could be off then:

d = {}
for x in Model.objects.all():
    d[x.country] = x

records_with_distinct_countries = d.values()
Sign up to request clarification or add additional context in comments.

2 Comments

This same thing can be performed with capturing the values in a set.
Not really. The countries can be put in the set as they are immutable. But the models are definitely not immutable, so can't be in a set. That's why I use a dict, the immutable country as key, and the record as value. I happen to use the dict keys as a set (which it conceptually is) without losing the record.
0
countries = [f.country in Model.objects.all()]

for c in countries:
    try:
        print Model.objects.filter(country=c)
    except Model.DoesNotExist:
        pass 

Comments

0

I think that @skrobul is on the right track, but a little bit off.

I don't think you'll be able to do this with a single query, because the distinct() method adds the SELECT DISTINCT modifier to the query, which acts on the entire row. You'll likely have to create a list of countries and then return limited QuerySets based on iterating that list.

Something like this:

maxrows = 5
countries = set([x.country for x in Model.objects.all()])
rows = []
count = 0
for c in countries:
    if count >= maxrows:
        break

    try:
        rows.append(Model.objects.filter(country=c)[0])
    except Model.DoesNotExist:
        pass

    count += 1

This is a very generic example, but it gives the intended result.

Comments

0

Can you post the raw SQL that returns what you want from the source database? I have a hunch that the actual problem here is the query/data structure...

Comments

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.