Using Django ORM to serialize data and related members - django

I'm currently working on a REST api, using django. I started using the nice djangorestframework, which I loved to use the "View" class.
But, I'm facing with the serialization problem.
I do not like the Serialization using the Serializer classes.
The main goal is to prepare a sort of giant dict, with all the infos, and give it to a renderer class which translate it into an xml, json, yaml, depending on the "Accept:" HTTP header. The goal is classy, but 60% of the CPU time is spend on creating the "GIANT DICT".
This dict can be created using django Models, but I think using on the fly instanciated classes and object is VERY un-efficient ? I'm trying to use some QuerySet methods to filter which models member I want to have, and getting a simple dict : the ::values() method, but unfornately, I can't access the m2m and foreignkey from my models.
Did you already tried this ? Any though ?

You could use the QuerySet's iterator method:
... For a QuerySet which returns a large number of objects that you only
need to access once, this can results in better performance and a
significant reduction in memory.
Your code should looks like:
for obj in SomeModel.objects.values_list('id', 'name').iterator():
# do something

Related

DRF - Serialize and Deserialize further explanation

I am starting to work with Django Rest Framework and I am a little confused with Serializers, sometimes its called to serialize and sometimes to deserialize, sometimes is called with the data param, and sometimes it doesn't. When and how is a good use for serializers to serialize and deserialize?
Serialization is the process of preparing your data to be sent ower the network in the case of REST. The result of the serialization is a json/xml in the case of Django REST framework. So you need to serialize your data when you get it, and you deserialize it when you save it to the model with a POST/PUT request.
For further reading: http://www.django-rest-framework.org/api-guide/serializers/
Serialization: Converting complex data types like queryset to native data types like dictionary.
DeSerialization: Converting python native data types to Complex data types.
so both the actions are accomplished with the same serializer. basically when we call a serializer with parameter data (like serializer=Serializer(data=data_dict), it return a complex object. and when we call it with complex object, it gives a dictionary.
So basically there is nothing like deserializer. Serializers perform both serialization and deserialization depending on the parameter we pass and that's how we call it.
we serializer data to send over the network so that it can be easily interpreted and rendered easily in the browser. we deserialize data to get complex object and to probably save it to database.
Thanks! Hope you find this helpful.:)

Django: Filtering a queryset locally from cache

If I perform a prefetch_related('toppings') for a queryset, and I want to later filter(spicy=True) by fields in the related table, Django ignores the cached info and does a database query. I found that this is documented (under the Note box) and seems to happen for all forms of caching (select_related(), already evaluated querysets, etc.) when another filter() is performed.
However, is there some sort of super secret hidden time-saving shortcut to filter locally (using the cache and not hitting the database) without having to write the python code to loop the queryset (using list/dict comprehension, etc.)? Maybe something like a filter_locally(spicy=True)?
EDIT:
One of the reasons why a list/comprehension doesn't work well for me is because a list/dict does not have the queryset methods. In my case, the first level M2M field, toppings, isn't the end goal for me and I need to check a 2nd related M2M field (which I have already pre-fetched as well). While this is also possible using list comprehension, it's just much simpler to have something such as filter_locally(spicy=True, origin__country='Spain') because:
it allows accessing many levels of related fields with minimal effort
it allows chaining other queryset methods
it's easier to read because it's consistent with the familiar filter()
it's easier to modify existing code using filter() without prefetch to add this optimization in without much changes.
But from the responses, Django has no such support :(
You have to write the python code to loop through the queryset (a list/dict comprehension is ideal). All the filter() code knows how to do is add filtering language to the SQL sent to the database. Filtering locally is a totally different problem than filtering remotely, so the solutions to those two separate problems won't be able to share any logic.
A list comprehension one-liner would be pretty straightforward, though; the syntax might not be much more complex than with filter().
If you're filtering on a boolean doing the list comprehension is pretty easy. You can also swap out the topping.spicy==True for a string comparison or whatever.
I would do something like:
qs = Pizza.objects.all().prefetch_related('toppings')
res = list(qs)
def get_spicy(qs):
res = list(qs)
return [pizza for pizza in res if any(topping.spicy==True for
topping in pizza.toppings.all())]
That is if you want to return the pizza object if any of its toppings is spicy. You can also replace the any() with all() to check for all, and do a lot of pretty powerful queries with this syntax. I'm somewhat surprised that there is no easy way to do this in django. It seems like a lot of these simple queries should be easy to implement in a generic manner.
The above code assumes a many2many. It should be easy to modify to work with a simple FK relationship such as a one2one or one2many.
Hope this was helpful.

packing objects as json with django?

I've run into a snag in my views.
Here "filtered_posts" is array of Django objects coming back from the model.
I am having a little trouble figuring out how to get as text data that I can
later pack into json instead of using serializers.serialize...
What results is that the data comes double-escaped (escaped once by serializers.serialize and a second time by json.dumps).
I can't figure out how to return the data from the db in the same way that it would come back if I were using the MySQLdb lib directly, in other words, as strings, instead of references to objects. As it stands if I take out the serializers.serialize, I get a list of these django objects, and it doesn't even list them all (abbreviates them with '...(remaining elements truncated)...'.
I don't think I should, but should I be using the __unicode__() method for this? (and if so, how should I be evoking it?)
JSONtoReturn = json.dumps({
'lowest_id': user_posts[limit - 1].id,
'user_posts': serializers.serialize("json", list(filtered_posts)),
})
The Django Rest Framework looks pretty neat. I've used Tastypie before, too.
I've also done RESTful APIs that don't include a framework. When I do that, I define toJSON methods on my objects, that return dictionaries, and cascade the call to related elements. Then I call json.dumps() on that. It's a lot of work, which is why the frameworks are worth looking at.
What you're looking for is Django Rest Framework. It handles related objects in exactly thew way you're expecting it to (you can include a nested object, like in your example, or simply have it output the PK of the related object for the key).

serialize a list of objects in json in Django

In my python code in views.py, i have made a list of Object instances. For example, if one of my objects in models.py is Sentence, then I at one point have an list of Sentences:
sentenceList = [Sentence1,Sentence2,...,SentenceN]
I have been happily using the template language in Django to send this off to a template where I can loop through the sentences in a template, but I am now implamenting some AJAX functionality, and would like to send something similar to this list "sentenceList" through a serialization through an AJAX portal.
It seems that I am between two worlds here though: the regular python JSON seiralizer, which serializes lists and python object, and simplejson, which only deals with pure Django Model queries.
Does anyone have a suggestion of how I should handle this (including not using lists of object instances if it is for some reason not good form)?
Thank you!
-Andrew
The Django serializer should be able to deal with a regular list of Django objects, according to the docs:
(Actually, the second argument can be any iterator that yields Django objects, but it'll almost always be a QuerySet).

Lazy loading relationships in Django (and other MVCs/ORMs)

Interested in knowing how lazy loading is achieved in frameworks like Django. When is the decision made to perform the join? And is there a way to force eager loading in Django? Are there times when you would need to force Django to eager load?
The general answer is that Django makes the decision to perform the query when you actually ask for some records. Most commonly this means iterating over the queryset (for record in queryset:) or using the list() built-in function to convert the queryset to a list.
See When QuerySets are evaluated for more specifics from the official docs.
It accomplishes this by defining a class, called QuerySet in django/db/models/query.py, where the special methods like __repr__, __getitem__ and __iter__ are coded to do the right thing.
If you need to force eager loading just run the built-in Python list function on the queryset, like:
qs = SomeModel.objects.all()
ql = list(qs)
This call to list() will perform the DB query and load all of the objects into memory. It should be pretty rare that you need to do this, but one case is when you need to use the query results in more than one place in your templates. Converting to list and passing the list in your template context will perform the query only once instead of once for every place in your template you iterate.