Should small specific views be implemented with Function Based views or CBVs? - django

I'm developing an app in Django and would like to know what is the correct way to implement some small views that need to implement some specific function. I'm still a beginner and I've been using CBVs from the start but I'm not sure if I should use FBVs for this.
I now need to implement some specific functions when integrating Stripe, for example, to reactive a canceled subscription or to upgrade a subscription and was wondering if I should use FBVs for this?
If not, should I for example use the POST of
class SubscriptionView(APIView):
def post(self, request):
# Make a new subscription...
that I use to create a subscription and just check if the user is trying to reactive/upgrade with a parameter or something like that?

Consider this chart if you are indecisive on what type of method to use.
But generally some of the advantages of using CBVs on my experience are:
They can be easily extended
Code re usability
Remove branching through the use of class methods, hence clean code.

Related

Django rest framework where to write complex logic in serializer.py or views.py?

I am new to Django Rest Framework. Using serializer and views a simple CRUD is easy. When the logics increase, it is quite confusing where to write logics in serializer or views.
Some developers do prefer "Thick serializer and thin views" and some developers "Thick views and thin serializer".
Maybe this is not a big issue and I think it is up to the developer whether to write more on views or serializer, but as a newbie what will be your suggestion to follow? Should I write more on views or serializer?
There are many answers on Django View Template but can not find a satisfying answer for Django Rest Framework.
Thoughts of experienced developers will be highly appreciated. Thank you.
Personally I prefer to have the business logic separated from both view and serializer. I usually create a new class with the business logic which can be used in both serializer and view based on necessity. Basically I treat it as a service. Reason for that is:
Makes the code cleaner(no thick and thin stuff).
Writing tests for those business logic is easier.
You can use that this business logic service in both view and serializer, depending on your need.
while testing APIs, you can mock those buiness logic if needed.
Reuse any logic in multiple places.
An example would be like this:
class BusinessLogicService(object):
def __init__(self, request):
self.request = request
def do_some_logical_ops(self, data_required_one, data_required_two):
# do processing
return processed_data
Example usage in serializer:
class SomeSerializer(serializer.Serialize):
...
def create(self, validated_data):
business_logic_data = BusinessLogicService(self.request).do_some_logical_ops(**validated_data)
return Model.objects.create(**business_logic_data)
I've asked a similar question about this before. Actually, it depends on what logic you are going to adapt. After doing further research, I have come up with some approaches. Here are my suggestions:
If you want to add some logic before doing serializer validation, it is better to include that in your view (eg. override your views create method). An example to this case would be; your POST body does not contain a value that is needed by the serializer hence is not valid yet, so add that in your view's create function.
If you are doing some custom authentication logic, such as parsing a custom token in your http header, do it in your view as well, because serializer has nothing to do with it. Moreover, you can create your own authentication decorator for that.
If you want to add logic which is directly related to the representation of your data, such as an adaptation of a timestamp from UTC to some other, you can add in your serializer as it is directly related to your object representation. You can use SerializerMethodField etc. to do that.
I try to segregate it on the basis of requirements of the context. Like:
If I'm supposed to deal with the request object(like current user), I try to implement that in view.
If I need to deal with querying models to create a view I would switch to serializer.
It may also depend upon how I'm planning to maintain the code (If I have huge number of views in a single file, I will try to avoid implementing logical stuffs as much as possible).

Good Django design practice to add a REST api later following DRY

I am starting a web application in pure Django. However, in the future, there might be a requirement for REST api. If it happens, the most obvious choice will be Django REST framework.
Both the "old-fashioned" and REST parts share the models, however, the views are slightly different (permissions definitions, for example) and forms are replaced with serializers. Doing it the most obvious way would mean to duplicate the application logic several times, and thus a failure to follow DRY principle, and so the code becomes unmaintainable.
I got an idea to write all the logic into models (since they are shared), but in such case, there will be no use of permission mixins, generic views and the code would not be among the nicest ones.
Now I ran out of ideas. What is the best practice here?
I'd try to keep things simple as you're not sure about the future requirements for the API, and guessing can introduce extra complexity that may not even be needed when requirements will be clear.
Both Django forms and Rest Framework serializers already offer you a declarative approach that abstracts away the boilerplate code needed for basic stuff, which normally accounts for most of your code anyway.
For example, one of your Django form could look like this:
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
And in the future the DRS serializer would be:
class ArticleSerializer(ModelSerializer):
class Meta:
model = Article
fields = ['title', 'content']
As you can see, if you try and stick to ModelForm and ModelSerializer, there won't be much duplication anyway. You can also simply store the fields list in a variable and just reuse that.
For more custom things, you can start by sharing logic into simple functions, for example:
def save_article_with_author(article_data, author_data):
# custom data manipulation before saving, consider that article_data will be a dictionary either if it comes from deserialized JSON (api) or POST data
# send email, whatever
This function can be shared between your form and serializer.
For everything related to data fetching, I'd try to use Model Managers as much as possible, defining custom querysets that can be resued e.g. for options by forms and serializers.
I tend to avoid writing any logic that doesn't directly read or write data into the model classes. I think that couples too much the business logic with the data layer. As an example, I never want to write any auth/permission checks into a save() method of a model, because that couples different layers too tightly.
As a rule of thumb, imagine this scenario: you add say permissions checks or the logic to send an email when a user is created overriding the save() method of your Article model.
Then, later on you're asked to write a simple manage command that batch-import users from a spreadsheet. At this point, what you did in your save() method really gets in the way, as you can freely access your data through your model without having to bother with permissions, emails and all of that.
Regarding the view layer and assuming you need to implement some shared auth/permission checks and you don't want to have separate views, you can use this approach:
https://www.django-rest-framework.org/topics/html-and-forms/
Blockquote
REST framework is suitable for returning both API style responses, and regular HTML pages. Additionally, serializers can be used as HTML forms and rendered in templates.
Here's some guidelines on how you could dynamically switch from HTML to JSON based to the request content type:
https://www.django-rest-framework.org/api-guide/renderers/#advanced-renderer-usage
This seems like a good option in your situation, I'd just write down a quick proof-of-concept before you go all in to see if you are not too limited for what you need to do.

Django CBV repeating the same query on each page

I am now using Class Based View in my Django application and it helps me a lot to develop faster.
I still have a question about the best way to implement the following:
I have some information in my database I need to always have in almost every template I have (except the template where user is not logged in).
What is the good method to make this using Django ? Is it okay to create a class based view with a custom query in the .get() method?
Thank you :)
There are various different ways to do this.
If you are consistently using class-based views everywhere, you could create a common base class with a custom get_context_data method that adds your specific data to the context dictionary.
But the more usual ways of solving this problem are nothing to do with class-based views, but apply to all sorts of views. They are custom template tags and context processors.
For me, a context processor is probably the best bet: as long as you ensure that your template is rendered with RequestContext (which it will be if you use any view that inherits from TemplateView) then your extra data will always be added to the template context.

django form methods are for validation only or not?

While I am studying the new django docs on class-based views, I notice this example code:
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
The fact of seeing send_email as a method of ContactForm really annoys me. I have always thought form methods should be for validation purpose and methods that consume forms (like send_email in this case) should be in the views layer. Am I missing anything here? Or should the example be corrected?
There is no correct answer for this one. It really depends on your coding style. Using a form for more than just validation is as valid as doing this method in the view.
The above example has some kind of advantage though. Lets say you have one model and you want to use different forms (with different logic) for it. Instead of putting the logic in the view and check which form is now used it probably better to put this logic on the form level.
The first time I got the same weird feeling was when I encountered the LoginForm from django.contrib.auth that also verifies that the user's browser is capable of working with cookies aside from managing the credentials passed in.
Personally, I agree with you. I'm more inclined to think that the view should be the responsible actor for performing the action of sending the email rather than the form and that send_email should be a method defined in the view.
But, then again, you can easily observe how a lot of us use Django differently or have a different approach to solving the same problems. Due to the fact that we have different concerns in mind when developing our applications, it's quite possible we have a different understanding of how certain framework components are meant to be used, which is a bit of a moot point. In the end, what's important to acknowledge is that it's possible to delegate some of the heavy-lifting from the view to the form in a manner that's well-defined.
There is nothing wrong with the example. For any but the simplest of cases, your form will contain only cleaning methods; most forms do extra validation and other actions. In the end, it is just a Python class and you can do whatever you would like in it; there is no "rule" except maybe DRY.
We have form methods that validate against external services, call other procedures and trigger workflows. For such complicated logic, it is best to embed it in to the form class as it increases reusability of the code. Developers working on the view simply use the form class as a library and don't have to worry about exotic validation requirements. In this case, it actually promotes DRY.
When we have to update the logic we only update the form class's "private" methods (those prefixed with _). This keeps the "public" interface (documented by django) intact and all view code using that form doesn't have to be updated.

Sharing view logic in Django

I've begun diving into Django again and I'm having trouble finding the parallel to some common concepts from my life in C#. While using .NET MVC I very often find myself creating a base controller which will provide a base action implementation to take care of the type of stuff I want to do on every request, like retrieving user information, getting localization values.
Where I'm finding myself confused is how to do this in Django. I am getting more familiar with the MVT concept but I can't seem to find how to solve this scenario. I've looked at class based views and the generic views yet they didn't seem to work how I expected. What am I missing? How can i create default logic that each view will be instructed to run but not have to write it in each view method?
If it is truly common for your whole site you use middleware. If it is only common for some views, the way to go in my opinion is to create decorators for those views. I never use class-based views because I tend to keep views simple and put more logic into models, so I have no need for classes there.