Django third-party library views: determining async vs sync - django

I want to incorporate async into my Django library. If I have a Django library that has 1) a sync view and 2) a urls.py that points to that sync view, how do I support both sync and async?
Presumably, I could ask the developer to set a setting to LIBRARY_ENABLE_ASYNC, then in views.py, I could write:
from django.conf import settings
if settings.LIBRARY_ENABLE_ASYNC
async def view(request): pass
else:
def view(request): pass
But that doesn't seem quite... right? Admitedly, I believe because we integrate with the Django ORM, we'll be splitting the views into two separate files/directories/and urls.py files, and the developer would simply include() the correct urls.py based on whether they're using ASGI/WSGI, but in the event the above does happen, is there a better way to determine whether a user is using ASGI/WSGI?

Related

Django REST - Serialize User.get_all_permissions

I am building an application with a Django Rest backend, and a VueJS front end and am working through authorization and authentication. I have the authentication working well, but am a bit stuck on letting the front end (VueJS) know what the user has authorization to do in terms of Add/Change/View/Delete for a model. For example, if a user cannot add a customer, I don't want to show the 'Add Customer button'.
Working through the Django docs, and solutions on StackOverflow, I believe the simplest way is to send the user's permissions from Django to VueJS.
The 'best'/'simplest' way I can see to get the permissions is with the following:
userModel = User.objects.get(request.user)
return User.get_all_permissions(userModel)
Where I am stuck is exactly where to put this logic and how to serialize it. Does the above belong in the View, Serializer, other? Up until now, I have only been working with Models (ModelSerializers and ModelViews), but I don't believe this falls into this category.
Thanks in advance...
You should add this logic to views, because the views are used to implement these kinds of logic.
Actually, you don't want to use serializers here, because of the response of .get_all_permissions() method is already in serialized form
Apart from that, your provided code is not good (it's clearly bad). It should be as below,
return request.user.get_all_permissions()
because, you'll get current logged-in user's instance through request.user, to get his/her permissions, you all need to call the get_all_permissions() method
Example
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
#permission_classes(IsAuthenticated, )
#api_view()
def my_view(request):
logged_in_user = request.user
return Response(data=logged_in_user.get_all_permissions())

Django: Avoid HTTP API calls while testing from django views

I'm writing the tests for django views, Some of the views are making the external HTTP requests. While running the tests i dont want to execute these HTTP requests. Since during tests , data is being used is dummy and these HTTP requests will not behave as expected.
What could be the possible options for this ?
You could override settings in your tests and then check for that setting in your view. Here are the docs to override settings.
from django.conf import settings
if not settings.TEST_API:
# api call here
Then your test would look something like this
from django.test import TestCase, override_settings
class LoginTestCase(TestCase):
#override_settings(TEST_API=True)
def test_api_func(self):
# Do test here
Since it would be fairly messy to have those all over the place I would recommend creating a mixin that would look something like this.
class SensitiveAPIMixin(object):
def api_request(self, url, *args, **kwargs):
from django.conf import settings
if not settings.TEST_API:
request = api_call(url)
# Do api request in here
return request
Then, through the power of multiple inheritence, your views that you need to make a request to this api call you could do something similar to this.
class View(generic.ListView, SensitiveAPIMixin):
def get(self, request, *args, **kwargs):
data = self.api_request('http://example.com/api1')
This is where mocking comes in. In your tests, you can use libraries to patch the parts of the code you are testing to return the results you expect for the test, bypassing what that code actually does.
You can read a good blog post about mocking in Python here.
If you are on Python 3.3 or later, the mock library is included in Python. If not, you can download it from PyPI.
The exact details of how to mock the calls you're making will depend on what exactly your view code looks like.
Ben is right on, but here's some psuedo-ish code that might help. The patch here assumes you're using requests, but change the path as necessary to mock out what you need.
from unittest import mock
from django.test import TestCase
from django.core.urlresolvers import reverse
class MyTestCase(TestCase):
#mock.patch('requests.post') # this is all you need to stop the API call
def test_my_view_that_posts_to_an_api(self, mock_get):
response = self.client.get(reverse('my-view-name'))
self.assertEqual('my-value', response.data['my-key'])
# other assertions as necessary

Django Redirect after Successful Login

I have a requirement that whenever I login or attempt to request a view that has a login_decorator then the next page be a page where I am required to ask the user to select a business entity (irreespective of the original view requested).
Let's say that the page is http://127.0.0.1:8999/APP/business_unit
To achieve this I configured the following in my settings.py
LOGIN_REDIRECT_URL='/APP/business_unit_selector'
Now when i try to access http://127.0.0.1:8999/APP/range_list
the page goes to http://127.0.0.1:8999/APP/login?next=/APP/range_list I was expecting that the next page after login be /APP/business_unit
but instead, the next page was /APP/range_list
The browser address bar has http://127.0.0.1:8999/APP/login?next=/APP/range_list
Is it possible to achieve what I am trying in Django?
LOGIN_REDIRECT_URL is used unly when next is unspecified. In your test request there is next=/APP/range_list - and that address is used to redirect user after login.
Probably the easiest and most effective solution is to make your own decorator, similar to login_required which redirects to /APP/business_unit_selector&next=<redirect_url> if unit is not selected, and apply it together with login_required. It is not the most efficient solution in terms of redirects number, but is quite clean, and doesn't mess up the login page.
You will also have to handle next parameter in your business_unit_selector view, if you like to achieve natural flow.
Your decorator should be something like
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.http import urlquote
import functools
def business_unit_required(view):
#login_required # probably you want to incorporate it here
#functools.wraps(view)
def wrapped(request, *args, **kwargs):
if not 'selected_business_unit' in request.session:
return redirect('%s?next=%s' % (
reverse('business_unit_selector'),
urlquote(request.get_full_path())))
return view(request, *args, **kwargs)
return wrapped
The reason that http://127.0.0.1:8999/APP/login?next=/APP/range_list is redirecting you to range_list after logging in, is because with next= you are overriding what is specified in your settings file, LOGIN_REDIRECT_URL='/APP/business_unit_selector'.
If I understand correctly you need to user to choose a business entity after logging in.
A couple solutions that come to mind are as follows:
1.) Don't use a separate forms for login and business entity. Instead combine them.
Username
Password
Business Entity
2.) You can also specify in your view if the user doesn't have a buisness entity ResponseRedirect("/APP/business_unit_selector")
docs here

On/Off Django app at specific date

I am creating a Django Project(which has a lot of Django apps in it) and I need some help.
I only need to add a small feature.
The admin will decide a date upto which the app will be shown to all.
I want the app to automatically redirect all users to a specific page after the mentioned date.
How should I proceed ?
A simple middleware (https://docs.djangoproject.com/en/1.7/topics/http/middleware/) will resolve your requirement. Something like this:
import datetime
from django.conf import settings
from django.http import HttpResponseRedirect
class OnOffMiddleware(object,):
def process_request(request):
if datetime.datetime.now() > settings.SHOW_DATE:
# Should redirect people
return HttpResponseRedirect('redirect to a specifc page')
else:
# Continue as usual
return None
Put the above in a module somewhere in your project and add it to the top of your MIDDLEWARE_CLASSES setting (https://docs.djangoproject.com/en/1.7/topics/http/middleware/#activating-middleware).

In which order to sort my middleware path match requirements?

I created a middleware which allows me to use a list of dictionaries to specify some access rules for any of my views. Each of these dictionaries looks like this:
REQUIREMENTS=(
{'viewname':'addtag',
'permissions':'can_add_tags'},
{'regex':re.compile(r'^somestart'),
'user_check':lambda request:request.user.username=='sam'}
)
In my middleware i then try to find out which of those requirements match the current request. To do so, i filter the complete REQUIREMENTS, and in the filter function i use this code to check if the path matches:
def process_request(self,request):
def path_matches(self,req):
path_matches = False
if (req.has_key('url') and req['url'] == request.path ) or\
(req.has_key('regex') and req['regex'].search(request.path)) or\
(req.has_key('viewname') and resolve(request.path).url_name==req['viewname']):
path_matches=True
return path_matches
requirements = filter(path_matches,REQUIREMENTS)
# now use the returned requirements to determine if a user
# matches the requirement and
My question now is: in which order should i use the checks? It's pretty clear that the check for the url is the fastest, so this has to be first. But then the question is if the regex search or django's url resolve function should follow first.
As i do not have any performance issues right now, this is more of an academic question. And if someone would have an all better solution to solve this, that would be even better.
edit:
To react to the given answers: what i'm trying to do is to create a possibility to restrict views of several external apps in a single file. So decorators are not an option, as long as i do not want to do something like this:
from ext_app1 import view1,view2
from ext_app2 import view3
#permission_required('can_do_stuff')
def view1_ext(*args,**kwargs):
return view1(args,kwargs)
which would lead to rewriting the url specifications each time i change permissions. I want to avoid that. Additionally my solution allows for a user_check function to do a check on a user like this:
def check_user(user):
if len(Item.objects.get(creator=user,datetime=today)) > 3:
return False
return True
That would be a simple way to, ie., restrict how many items a user can upload each day. (Ok, that would be possible with user_passes_test as well).
One more thing is that i sometimes want to check for a permission only if the request is a POST, or if the request contains a certain key:value pair (like 'action':'delete' should require the permission, while 'action':'change' should be allowed for anyone). This could be done with a custom decorator as well, but as soon as i would need a new check, i would need a new decorator.
If you're using Django's built in user authentication and permissions system (django.contrib.auth) then you should consider using the views decorators it provides instead of a middleware. These give you several advantages:
Code that changes together is in the same place, i.e. it's more likely that you'll need to change permissions for a specific view when you are changing the view's code than when you are changing other permissions.
You don't have to write much of the code yourself, which makes your project smaller and easier to maintain.
For simple situations you can use the login_required and permission_required decorators, and for a more complex condition the user_passes_test decorator allows you to check if the user passes any condition you care to specify.
The code looks something like this for a view function (example is lifted from the documentation):
from django.contrib.auth.decorators import permission_required
#permission_required('polls.can_vote')
def my_view(request):
...
If you're using class-based views then it looks a little different (again, this example is lifted from the documentation):
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
If you have a good reason not to use Django's permissions system, then you can still adopt a similar approach. The code for the django.contrib.auth decorators could easily be used as the basis of your own decorators.
You might be looking for user_passes_test decorator.
You can decorate the views you need instead of using a middleware.
The code will looks like this:
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda user: user.has_perm('model.can_add_tags') \
and user.username == 'sam')
def my_view(request):
...