Django form validation vs DRF serializer validation - python

I'm new to APIs creation in django.
I checked DRF serializers and I found them useful when manipulating models in DB. My APIs don't use models they are based on forms.
So my question is : what can I get more from using DRF validators then using django forms validators in my views ? maybe the content type is more convenient (application/x-www-form-urlencoded vs application/json) ?

DRF's serializers are nicely integrated within the framework. Whether they are models based or not, you will have a nice browsable UI to play with for free and you can get OpenAPI schema generation. There are probably other things I did not think of.
What serializers can do that forms can't:
Nested data - although you can get some results with formsets.
Hyperlinked relational fields
Difference between an empty field and a blank field - HTML forms can't do that
out of the box integration with generic class based views or viewsets
Please note that your can still benefit from DRF even if you are not using serializers. DRF parts are loosely coupled.

Related

DRF - Sending extra data to browsable api

Sorry for my poor language usage.
I am using drf for my web api. It has special renderers. I can use django views, or drf pure APIView. I can use TemplateHTMLRenderer which is good but all of them make drf not necessary. Because i want to use drf browsable api features. Using post, put, delete forms. Using json and html in api, less and clean code.
But the problem is, i cant customize browsable api, i cant send extra content or context. For example; i am using serializer for my Post model but also i need another query serializer too. Which they are not related actualy.
Too much talk. My question is; i want to customize browsable api with his features and with more extra data. But i could not see any documant for it.
Thanks.
This methods are sending data with content in response which is in json data.
https://github.com/encode/django-rest-framework/blob/master/rest_framework/renderers.py#L686-L722
like here. I can use content or view, or forms in my api.html and I want to add more data here. Like;
'mydata': Posts.objects.all(),
'mydata2': Blogs.objects.all(),
and after that, i want to use them in my api.html(or in custom template).

Difference between django.core serializers and Django Rest Framework serializers

I am now learning Django and I just heard about Django Rest Framework (DRF). I was wondering what is the difference between the django.core serializers and the rest_framework serializers. Yes, I know DRF is for APIs.
django.core serializers are meant for the purpose of serializing entire model instances into XML, JSON, or YAML, and vice versa. They don't do anything besides just serializing.
DRF's serializers are specifically for converting model instances into JSON objects when dealing with data from HTML forms or API requests. Thus, serialization is not always a smooth or straightforward process, as you may be passed illegitimate or incomplete data, or fields of the form may not correspond in an obvious way to the fields of the corresponding model(s). For this reason, DRF allows you to create custom subclasses of serializers.Serializer in order to clean and validate data that is passed to the server. This also allows you to customize the manner in which the data is stored in the model instance. See the documentation here.

User model other than AUTH_USER_MODEL in Django REST Framework

I have an architectural problem. I'm using Django (with admin panel) and DRF (api with stateless authentication using JWT).
Django has Admin users represented by model which is more or less the same as default Django User Model. Admins work with Django Admin only and can't use DRF api.
DRF has API users that are allowed to use only api through DRF and can't interact with Django Admin or Django Session etc.
I know that the best approach is to use multi model inheritance, like:
class User(DjangoUserModel):
pass
class Admin(User):
pass
class API(User):
pass
AUTH_USER_MODEL = "User"
but the problem is that, those users are completly different. Eg: API user has complex composite key as an username field which is impossible in combination to simple Admin username field. And many other differences. ..
The question is: may I use a user object that is not an AUTH_USER_MODEL instance in DRF? So self.request.user will store a model instance that isn't connect in any way with an AUTH_USER_MODEL. Has any of you done something similar?
Well, yes sir. You can do that. Look at the following example:
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class AuthenticatedServiceClient:
def is_authenticated(self):
return True
class JwtServiceOnlyAuthentication(JSONWebTokenAuthentication):
def authenticate_credentials(self, payload):
# Assign properties from payload to the AuthenticatedServiceClient object if necessary
return AuthenticatedServiceClient()
And in settings.py:
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None,
'DEFAULT_AUTHENTICATION_CLASSES': (
'myapp.authentication.JwtServiceOnlyAuthentication',
),
}
If you want, you can define additional DEFAULT_AUTHENTICATION_CLASSES for your DRF. The authentication classes are just like middleware, just a queue that is populating request.user.
Adding your own authentication classes that are using diffrent user model from AUTH_USER_MODEL will work exactly as you would except.
Since you are using Django and DRF, perhaps you can write an APIUser model which extends from AbstractBaseUser with your customizations, write a custom authentication class and plug that into the REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES setting. Leave AUTH_USER_MODEL alone for the django admin.
Your custom authentication may just need to override authenticate_credentials (i've referenced the TokenAuthentication class in DRF github) and return an APIUser rather than the default defined in settings.AUTH_USER_MODEL. This will be a bit different because you're decoding a JWT, so you'll likely be extract some info from your JWT and looking up your APIUser by whatever means you need, such as your composite field. This should result in self.request.user being an APIUser for your DRF API views.
You're API views should be using the rest framework's settings, and your Django admin should be using the regular django settings. There may be some other caveats, but generally you'll be ok with just this I think.
One thing that I immediately recall is how Mongoengine used to hack the whole django authentication system. Mongoengine < 0.10 has a django compatibility app that implements a crutch to store users in MongoDB and make them accessible via self.request.user.
It has to use a crutch, because Django Session API is opinionated and assumes that you're using AUTH_USER_MODEL, backed by SQL database for storing your users.
So, I think you should disable SessionMiddleware and CSRF token handling and use 2 distinct custom authentication systems for Admin and API purposes. With TokenAuthentication or JWTAuthentication this should be doable.
Here's another example of a project with DRF and Mongoengine, with a custom implementation of TokenAuthentication, backed by MongoDB.

What is the recommended approach to implement admin-actions-alike functionality outside admin?

I've been searching a way to reproduce admin-actions behavior on my own tables using django-tables2. I haven't found any module to introduce this functionality to a ListView to derive from it and looking at ModelAdmin I see there are many methods implied on this.
Of course, I can add a form around my table to get the checkboxes and a submit button pointing to a view that works with the ids but I'm looging to get a combo to choose among different actions as in django-admin but also to have that 'actions' meta option to list some methods as the possible actions to perform.
I found django-actions which is still very young but also it introduces it's own page for operations and I just need to integrate functionality on my own model so I can connect some input type=select with the model actions.
Any comment is appreciated :)
There is no built-in solution for it. You have to implement your actions in your views and the functionality to your templates.
Add, edit and delete operations are very easy to implement in your views.py. This depends on your models, but you can trigger database manipulations from within your templates and keep the logic in your views.py.
You can also easily add a form to your templates as it is described in the docs:
# forms.py
from django.forms import ModelForm
from myapp.models import Article
# Create the form class.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
model := Choose your model which you want to modify / add
fields := Select some fields from your model, which you want to show up in your form
This defines a form corresponding to your model, which can be used in your templates to modify or add an entity to your database.

How to utilize django generic view?

For example, I want a page, which will let user add data for different categories of goods.
Like:
Model: Category is foreign key of item
Category1(detail url):
Item 1(detail url):
Date(textbox), Amount(textbox), Price(textbox)
Item 2:
...
Category2:
...
Save button, add more button, etc...
Since this is an example, I what those thing all display in a page.
I don't mind hard writing them with normal functions, but I wonder if I can utilize the views, since if they are so heavily introduced and developed, they might be powerful. So why not utilize it?
Can anyone tell me tricks about how to use them or we shouldn't use them if we want more functionality?
Django's generic views cover a lot of common use cases. For example:
CreateView - a view for creating an instance of a model
UpdateView - a view for updating an existing instance of a model
DeleteView - a view for deleting an existing instance of a model
DetailView - a view for displaying the details of an exsting instance of a model
ListView - a view for displaying a list of instances of a model
There are more around if you need them, and they cover the majority of views you are likely to need. You can also extend them to meet your needs quite easily. As a general rule of thumb, they make such a huge difference to how quickly you can get something built that I would recommend using them by default, and only switching over to writing your own views when absolutely necessary. If you haven't yet learned them, I think doing so will be a very good investment of your time - you will make up the time spent very quickly. For a lot of view types, it's just a case of specifying the model, setting up the URLs and the template, and you're done.
If you need to pass through additional data, then you can extend the generic view in question and override the get_context_data() method. If the same needs to be applied to several different generic views, you can create a mixin that includes that method and include it in that generic view.
For views that include forms, like the CreateView and UpdateView, as Drewness said, you can pass through a ModelForm instance to tell it what form to use, and that form can itself be overriden, so you still have a lot of control over what the form will do. For instance, you might define the following form:
from django.forms import ModelForm
class CategoryForm(ModelForm):
exclude = ['date_created']
And the following view
from django.views.generic.edit import CreateView
class CategoryCreateView(CreateView):
model = Category
form_class = CategoryForm
The Django tutorial covers generic views pretty well.
You can use Django's ModelForm with a FormView.
Then all of the fields in your model will be available in your form and in your form view. You should also look at mixins. Mixins allow you to use combinations of class-based views.
Finally, if you want to use more than one form (model) in a view you can use a FormSet.

Categories