Multi-tenant issue using django-rest-framework - python

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 ?

Related

Re-usability of code between django and django rest framework

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/).

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).

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.

How to do a Customer Logger for Django to Capture Response and Request

I'm looking into differen't ways to capture the response object, request object, and performance in Django to create a custom json elk logger that will build audit logs.
I'm not sure what approach is best to take here. I was looking at custom middleware but I've never done that.
I tried to look up if it was possible to use a decorator to do this but doesn't seem like it.
Also, I use the django rest framework so I also have to figure out how to integrate the middleware if thats the route or whatever solution to DRF as well.
Looking for suggestions.
If you use DRF, i advice you pckage - drf-tracking. Just add mixin LoggingMixin to you class like this:
class ProbeView(LoggingMixin, APIView):
...
And after this, each qyery for this view wiil be logged in database. Example:

Categories