Search code examples
djangopython-3.xdjango-1.7

How to combine select_related() and values()?


I am asking this question again (it was asked back in 2009),

We know there is a values() method of QuerySet, when there is a foreignkey (author, for example), it result like:

[{ 'author_id':3, ... }, ...]

I want a result like:

[{ 'author':{'name':'dave',...}, ... }, ...]

Has something changed in the newer versions of Django?

I want to convert the query set into a combination of lists and dictionnaries, is it possible?

I will then take this object and place it into a bigger object to serialize it. It is the reason why I don't want to serialize it right away.


Solution

  • Accepted answer is good but I was using django rest framework and it was a little bit hard for me to generate nested structure, using .only instead of .values you can force it to return normal objects from database:

    Book.objects.select_related('author').only('author', 'title', 'created_at')
    

    It will return a normal query set which allows you to use django serializers:

    class BookSerializer(serializers.Serializer):
        title = serializers.CharField()
        author = AuthorSerializer()
        created_at = serializer.DateTimeField()
    
    

    Now you can simply do this:

    qs = Book.objects.select_related('author').only('author', 'title', 'created_at')
    sz = BookSerializer(qs, many=True)
    print(sz.data)
    

    and sz.data will be a nested dict ready to be sent out.

    Also in this approach it uses LEFT OUTER JOIN as same as when you are calling select_related normally.

    Note1: Remember this functionality is tested on Django version 5.1.4

    Note2: .only is not like .values, it only defers loading the data from database, so if you access other fields on your retrieved objects, there will be new queries sent to database.