In the last post (I would recommend you give it a read before diving into this post) we described how we rewrote our old code to Django Rest Framework (DRF) serializers and views. Here, we will conclude the story with the Proxy classes we used to overcome the transition to DRF without making changes to our models and talk about how you should sometimes avoid DRF.
For the beginners among you and those who don’t know, when you look up the meaning of the word ‘proxy’, the first definition you usually come across is:
Proxy – the authority to represent someone else, especially in voting
This definition, or at least the first part, perfectly describes what we used Proxies for. Instead of making changes directly to our models, we used Proxies to represent them and provide us with imitation objects, which we later used. One of the reasons for doing this is the fact that all our changes can now be found in one place, inside the respected module folders.
Let’s take a look at our Group model, also used in the last blog post (models.py):
And here is our GroupProxy, which has all that is needed in our case (proxies.py):
As you can see, our Proxy actually returns an object that resembles the Group model’s serialize method. Allow me to continue with what the DRF documentation says about serializers:
“Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.”
In most cases, the get, post & put methods return Model instances, and the list method returns querysets, but the data we show differs from the Model data, so we instead return the Proxy objects. Of course, we could have overridden the serializer’s to_representation method, but this option is much more readable and DRY.
In the last post, I showed you what views and serializers look like, but I will make reference to them again so you can easily see the examples of where we use GroupProxy:
– Let’s start with our view (views.py):
As you can see, in the list() method we pass the serializer a list of GroupProxy objects, which it then converts to JSON format that we use.
The get_object() method is called inside the DRF retrieve() method, which also serializes the given object so we have to pass it a serializable object, just as we have in the list() method.
Here is what the retrieve() method inside ModelViewSet looks like:
You may be asking yourself: Why not just apply the logic from get_object() method to the above-mentioned method? Well, as they say, there is a place and time for everything, and in this case, there is a place for everything. DRF has been written to be as readable, overridable and maintainable as possible, so why change that and move logic elsewhere when it has its own place? Not to mention that you may omit an important part of the logic by rewriting it and then spend hours debugging, wondering why it doesn’t work.
Our logic for creating and updating objects is located in the overridden create() & update() methods of the serializer
create_group() & update_group() methods both return an instance of the Group model, which we then pass to our Proxy class, a serializable object used in the respected DRF views.
I would like to give a bit of advice to anyone using DRF in their projects, which I myself wasn’t taking into account until not so long ago, and that is, use “Classy Django REST Framework” the right way and your life will be much easier. Here are some simple, but useful and maybe obvious tips on how to use it:
- Use the “Collapse” & “Expand” features under the Attributes section when searching for occurrences of words/methods.
- Place the logic where it is supposed to be!
For example, you need to customize the creation of an object:
– The first thing you look for is a create() method in the view/viewset/mixin you are using.
– In it, perform_create() method is called, and there you can see serialize.save().
– Go to the designated serializer definition that is linked in the header of the site and look for the save() method.
– The serializer create() method is then called.
Do this a few times and you will remember all the steps, and also keep everything in its right place.
# Why you shouldn’t use DRF and when
For most things I cannot say enough in praise of DRF, but is it always the best choice? Sure, it helps for everything to stay concise, clean and saves a lot of boilerplate code, but sometimes, in my opinion, it can seem as an overkill. Or is it?
DRF includes both Class Based Views and function views by using the @api_view decorator. There are short examples for the latter on this link. The example shows how to use a function-based view with a serializer, which can actually be really useful.
This is all great, but what if you just want your API to return a simple YES or NO, start a timer or you simply don’t want to add another framework to your project?
In a project I was working on a while ago, we had a situation where we had to add a few APIs extremely fast, and since we were being outsourced and I wasn’t that confident about my DRF knowledge, we decided to add normal AJAX views. The views were supposed to create, rename, and change the position of a column in a board, and the like.
Here are two examples of the code:
As you can see, it took just a few lines of code in comparison with creating a serializer and a view in DRF. Today it would take me a little longer to do this in DRF, but for our purposes it was more than enough. The above function views were used on a single page, which consisted of objects that were part of only two models, and things had to happen when you made a change. Most of the site was written in JS, which also handled the errors for forms we had.
Finally, which is better? Honestly, today I would probably tell you not to be lazy and learn to use DRF, but for a beginner, this might mean biting off more than they can chew. I would also like to use AJAX views as easy solutions (as seen in the examples), but I usually almost immediately discard that option and go for DRF. Nothing is wrong with this code, but if you start working for someone who wants their product to grow and become widely used, then do yourself and those who will inherit the code a favor in the long run and opt for DRF.
Continue exploring the Dev Corner to meet our dev team and read a tech blog or two
Check out the t-matix main website if you are interested in the t-matix group and want to find out more about our solution as well as industries we cater
December 18, 2019
Continuosly building, testing, releasing and monitoring t-matix mobile apps