Re-usability of code between django and django rest framework - python

I have been assigned a project which has two versions of it: older one is written in django and new one written in django rest framework.
I am quite new to both django and drf. While going through both codebase, I came across following code in one of the views.py in new drf version:
def get_xyz(request):
# some business logic
return HttpResponse(json.dumps({ ... })
, content_type="application/json"
, status=status.HTTP_200_OK)
Then in older version of the app, I found function with exactly same above structure in its views.py. This created following confusions in me:
Can we use function based views (as above) written in (non-drf) django app as it is in drf based app?
Can we use class based views (as shown below) from non-drf django app as it is in the drf based app?
class AbcClass(View):
def get(self, request):
# business logic
return HttpResponse(json.dumps({ ... })
, content_type="application/json"
, status=status.HTTP_200_OK)
def post(self, request):
# business logic
return HttpResponse("success", status.HTTP_200_OK)
Does all django framework (non-rest) classes (like View above) work perfectly in drf?
Can we make frontend app written in react (or angular) send requests and receive responses from old django app (similar to how frontend apps built with these UI frameworks are usually made to communicate with APIs built in drf)?

Yes,
DRF extends the django framework by providing generics view and toolkit for them (routing, models, serializer, etc). But at the end, all it does is bind a function (the method of class based views) to a specific route/request. Django admin will still work without DRF, and any extra application that you already defined (and usually you bind those application to a api route using the url.py file).
For building an SPA with django, that's totally doable, as long as you return any type of data that your client can consume (usually application/json mime type). DRF is "only" a wrapper around django to do that (with a nice architecture, modular and decoupled features), but returning json in django is as simple as returning a JsonResponse object from your view function (https://docs.djangoproject.com/fr/4.1/ref/request-response/).

Related

Convert live Django project to REST API project

What is the best way to convert the project from django to django rest framework?
I have live django project, which is completely working, but now it want to convert the project into REST API.
I made the rest api for project which has new classes and function for the rest api with (form verification and same logic) copy from the django class which has been implemented.
So there is duplication of logic, so is there any way to do not replicate the logic and make running both of the classes django and django rest framework ?
Problem is when any update needed for any page then i have to code both side django and django rest framework , so there can be some mistake arise in copy.
One can create an API with Django using custom views but I advise one to use Django REST Framework (DRF) instead as it simplifies the process.
In short,
Install DRF with pip install djangorestframework (add it as well to the INSTALLED_APPS in your settings.py file).
Create a serializer per your needs (DRF has built-in serializers, like ModelSerializer). Note that OP can definitely use the models that OP already had in Django.
Create the views (DRF has generic views) and specify the URLs to access the views.
Let's say one has an app named books. In order to ensure the code isn't mixed between Django and the API, create an api folder inside of the books app and you should have something like this
books
-...
-api
--__init__.py
--serializers.py
--views.py
--urls.py
If OP wills, add reference to that urls.py in OPs main urls.py file,
urlpatterns = [
# ...
path('api/', include('books.api.urls', namespace='api')),
]

Create Django Model Instance using POST method in another Python Script

So I have a django app with some models which I can manipulate via admin and also through a client facing site, like add instances etc. However, I would like to try something a little different from that. I have a Python script that uses POST and JSON objects based on those self same models and I would like to be able to run it, connect to my django app server via a port and create new instances of my models (essentially without using Admin or my client page). Any ideas how I go about this?
If what the script does is simple, it may be easiest just to create a view which receives the JSON, processes it, and returns a JsonResponse.
e.g.
def create_object(request):
if request.method == 'POST':
data = json.loads(request.body)
# Do something with the data - e.g. create a model instance
MyModel.objects.create(**data)
return JsonResponse({'status': 'created'})
Alternatively, if the script does more complicated things or if you intended to expand it in future, you may be best to expose your site via a REST API using something such as Django Rest Framework.
With Django Rest Framework, you can fairly rapidly build CRUD based APIs around your models using components such as ModelViewSets and ModelSerializers and expose them over REST with minimal code.

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.

Django REST or simple Django for REST API

I would like to know if it is possible to build a REST Api using only Django (without Django REST).
I have following code in my views.py my Django (no REST Django)
from django.http import HttpResponse, JsonResponse
def get_something(request, object = None):
dummyDict = {'Debug':object}
return JsonResponse(dummyDict)
ulrs.py
url(r'^(?P<object>\w{1,50})$', views.get-something, name = "get-something"),
Can this work as REST API?
I tried testing using curl and I get following answer from my django server:
HTTP/1.0 200 OK
Date:
Server:
X-Frame-Options:
Content-Type: application/json
{"Debug": daodoaw}
You may do that though you'll have to add a lot of things to make an API RESTfull.
Your example is already missing proper response code for PUT / POST / PATCH / DELETE and doesn't respond correctly to OPTIONS
Ofcourse you can do these things with Django, but the advantage of django rest is that it is specifically created to handle api creation and management, Thus using django rest will be much more effective. When you look at the documentation of django rest, you could see that viewsets like ModelViewSet, GenericViewSet which are capable of handling any type of requests(POST, PUT, PATCH, etc...) in a two or three line code. Meanwhile while you using django you have to specify each and every case. Its just a case where DRF is more preferred).
What I try to say is, DRF is more handy in the case of API Creation and has a very good documentation in their official website
If you have to know about any specific part, please comment below
Thanks
Using Django is not a crime! We are given the liberty to use either DRFor Django.
Here are some of the situations when you can think of using DRF:
Let's imagine, you have developed a web application with django. What would happen if your client or you want a mobile version (android/iOS version) of your application? As multi-platform development is becoming the norm, using DRF can become crucial to reuse the same backend for both a mobile app and a web app.
Another comprehensive reason to use DRF is its super easy serialization facility.
If you want to segregate your front-end from Django provided templates, you are free to use modern javascript frameworks such as Vue, React or Angular for better design and to be dynamic as much as possible with your REST APIs.
When you use DRF, you are given ready-made view classes (ApiView, GenericAPIView, Viewsets) that are only a few lines of coding and able to handle all sorts of requests such as (POST, PUT, PATCH, etc...).
NOTE: Definitely, you can use Django depending on the project you are handling. In the case of building a web application that doesn't need to be accessed from other platforms, I would not use DRF. It entirely depends on the requirements.

Multi-tenant issue using django-rest-framework

We have an issue to make a multi-tenancy SaaS application using Django and django-rest-framework.
We would like to route to the correct database according to the url, and using django-rest-framework serializers.
But with django-rest-framework, we cannot specify the database we want to save to with serializers. We are able to request data by overriding the get_queryset method, and with the using(<database>) function.
class SomeSerializer(serializers.ModelSerializer):
def get_queryset(self):
return SomeModel.objects.using(self.database)
If we want to save an instance to a custom database, we cannot use ModelSerializer, we have to write each serializer using the Serializer class.
We can make a pull request to add the option to django-rest-framework Multiple databases support #65 - django-rest-framework
Or, we can do something similar to this snippet : Database Routing by URL, it's quite old (2010) but still working. But we are not very comfortable with the idea of using the local thread to transfer variables.
How do we do this properly in 2017 ? Are there other options ?

Categories