Django/Django Rest Framework - Disable CSRF - python

Im looking for a simple way to disable all the CSRF validation to can test my API in Postman.
Till now I have tried add #decorator csrf_exempt without success.
I also tried create a disable.py file inside the app, but didn't work also.
Also I want desactivate for all requests, so some way to dont have to add the decorator everywhere. This a project that I just got, is already in Production, but I want to start to write Tests first in Postman, later TestCases.
All my views are using a "api_generics.CRUDGeneric",
the declaration of that class is:
class CRUDGeneric(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin,
mixins.DestroyModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
thanks is advice

#62009030 you should be able to do what #smarber mentioned.. This could also work.. It is a traversed way to add csrf_exempt
from django.conf.urls import patterns, url
from django.views.decorators.csrf import csrf_exempt
import views
urlpatterns = patterns('',
url('^asimpleurl/$', csrf_exempt(views.CRUDGeneric.as_view())),
...
)
This could be a work around for your problem..

Related

Force user authentication in URL dispatcher of Django

I would like to restrict a specific path to authenticated users in urls.py. I know how to do it in views.py, the problem is that this is a module which I have installed using pip, so I do not handle it in my views, and I do not want to modify the source code of this module.
...
path('thispath/', include('module.urls')),
...
May I force an authentication in urls.py ? Or should do it in views.py as usual (or using decorators):
request.user.is_authenticated
I have found a solution. It should be done using decorators, but as it is an include, the default login_required decorator does not work.
So, one solution could be with django-decorator-include
from django.contrib.auth.decorators import login_required
from decorator_include import decorator_include
...
path('thispath/', decorator_include(login_required,'module.urls')),
...

remove authentication and permission for specific url path

I'm working with DRF and came across this issue. I have a third-party view which I'm importing in my urls.py file like this :
from some_package import some_view
urlpatterns = [
path('view/',some_view)
]
but the issue I'm facing is since I have enabled default permission classes in my settings.py like this:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
),
}
now when I call that view using the url , it gives me authentication error as I'm not providing token .Is there a way I can bypass authentication error without having to make changes in view directly,I know that we can remove permission for that particular view , but for that I'll have to make changes to that some_view function code. But I don't want to do that,let's say we don't have access to that function we can only pass data and receive response. How can I bypass authentication without having to change that functions code .
I tried searching but couldn't find what I'm looking for.
I was assuming that there might be someway we can do that from urls.py like specifying any parameter or something like that which make that particular view to bypass authentication without having to change functions code.
somthing like this :
from some_package import some_view
urlpatterns = [
path('view/',some_view,"some_parameter") #passing someparameter from here or something like that
]
Is it possible what I'm looking for ? Thanks in advance :)
So, the most appropriate way for third-party views is to use decorators by defining them inside your urls.py:
Case 1
I assume that some_view is a class inherited from rest_framework.views.APIView:
urls.py
from django.urls import path
from rest_framework.decorators import permission_classes, authentication_classes
from rest_framework.permissions import AllowAny
from some_package import some_view
urlpatterns = [
path('', authentication_classes([])(permission_classes([AllowAny])(some_view)).as_view())
]
Case 2
I assume that some_view is a simple Django view function and you need to define it for GET method:
urls.py
from django.urls import path
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import AllowAny
from some_package import some_view
urlpatterns = [
path('', api_view(['GET'])(authentication_classes([])(permission_classes([AllowAny])(some_view))))
]
Case 3
I assume that some_view is an api_view decorated DRF view function. This is the hardest and most probably the most impossible part because you have to undecorate the previous api_view decorator. If view function is decorated with api_view, then it is already converted into Django view function so neither permision_classes nor authentication_classes can be appended to class:
You can override the default authentication class to skip auth for specific urls.
For example:
class CustomIsAuthenticated(IsAuthenticated):
def has_permission(self, request, view):
# make a list of public urls
if request.path in PUBLIC_URLS:
return True
return super().has_permission(request, view)
You have to create a list of PUBLIC_URLS which bypass authentication.
Now use this class in the DEFAULT_PERMISSION_CLASSES in rest framework settings. And remove the default IsAuthenticated class.
Although I recommend the decorators approach.
check docs: https://www.django-rest-framework.org/api-guide/permissions/#allowany
Decorators approach is more verbose and by looking at the function you can make out if it is public or not.
#Bedilbek's answer worked for me, but if you'd prefer to use different syntax and define the permission_classes and authentication_classes inside your view instead of urls.py, you can do the following:
from rest_framework import permissions
from rest_framework.views import APIView
class SomeView(APIView):
permission_classes = [permissions.AllowAny]
authentication_classes = []

Serializing with django rest framework

I have the model named Artist and I want expose this model with Django Rest Framework to create an API and this data can be consumed.
I've created a class based view in artists/views.py named ArtistViewSet
#CBV for rest frameworks
from rest_framework import viewsets
class ArtistViewSet(viewsets.ModelViewSet):
model = Artist
I also have an url named api/ in the urls.py file (view third url named api/) which the user could access to the view above mentioned.
# coding=utf-8
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
admin.autodiscover()
from rest_framework import routers
from artists.views import ArtistViewSet
#I create a router by default
router = routers.DefaultRouter()
#Register the model 'artists' in ArtistViewSet
router.register(r'artists', ArtistViewSet)
urlpatterns = patterns('',
(r'^grappelli/', include('grappelli.urls')), # grappelli URLS
url(r'^admin/', include(admin.site.urls)),
#Include url api/ with all urls of router
url(r'^api/', include(routers.urls)),
)
When I go to my browser and type http://localhost:8000/api/ I get this message error:
What did can be happened me?
In Django REST framework 2.4+ (including 3.0+), the model attribute for views has been deprecated and removed. This means that you should be defining your view as
from rest_framework import viewsets
class ArtistViewSet(viewsets.ModelViewSet):
queryset = Artist.objects.all()
Which should give you the result you are expecting. Now, you asked in the comments
I cannot understand the role of base_name. I mean, this base name is the url that I've created? My viewset ArtistViewSet does not have a queryset attribute, due to this, according to documentation, it's necessary put the base_name argument, but i don't know how to do it.
The base_name that can be optionally defined when registering a ViewSet is used when naming the automatically generated routes. By default, the format is [base]-list and [base]-detail, where [base] is the base_name that can be defined. When you do not specify your own base_name, it is automatically generated based on the model name. As the queryset method must be defined for ViewSet instances, this is where the model (and later model name) is retrieved. As you did not provide the queryset argument, Django REST framework triggers an error because it cannot generate a base_name.
To quote from the documentation on routers
Note: The base_name argument is used to specify the initial part of the view name pattern.
The documentation goes on to further explain exactly why you are getting the issue, even including an example, and how to fix it.

Django / From redirect_to to RedirectView

Since you know, we can't use from django.views.generic.simple import redirect_to in Django 1.5. However we were using this kind of functions in our views.py:
return redirect_to(request, '/auth/login/')
I want to migrate from 1.4 to 1.5 but I couldn't figure out how to use RedirectView in views.py with request and url argument.
You can use redirect instead
Now you can simply change the redirect_to to
return redirect('/auth/login')
You can use Class based views or RedirectView
RedirectView helps you to redirect your url which works as like redirect_to. Both are applied in urls.py. But I couldn't find any solution to redirect from views.py.
Source: "No module named simpleā€ error in Django

Customized views with django-registration

I need to make a very simple modification -- require that certain views only show up when a user is not authenticated -- to django-registration default views. For example, if I am logged in, I don't want users to be able to visit the /register page again.
So, I think the idea here is that I want to subclass the register view from django-registration. This is just where I'm not sure how to proceed. Is this the right direction? Should I test the user's authentication status here? Tips and advice welcomed!
Edit
I think this is the right track here: Django: Redirect logged in users from login page
Edit 2
Solution:
Create another app, for example, custom_registration, and write a view like this (mine uses a custom form as well):
from registration.views import register
from custom_registration.forms import EduRegistrationForm
def register_test(request, success_url=None,
form_class=EduRegistrationForm, profile_callback=None,
template_name='registration/registration_form.html',
extra_context=None):
if request.user.is_authenticated():
return HttpResponseRedirect('/')
else:
return register(request, success_url, form_class, profile_callback, template_name, extra_context)
I had to use the same function parameters, but otherwise just include the test, and if we pass it, continue to the main function.
Don't forget to put this in your URLConf either (again, this includes some stuff about my custom form as well):
top-level URLConf
(r'^accounts/', include('custom_registration.urls')),
(r'^accounts/', include('registration.urls')),
custom_registration.views
from django.conf.urls.defaults import *
from custom_registration.views import register_test
from custom_registration.forms import EduRegistrationForm
urlpatterns = patterns('',
url(r'^register/$', register_test, {'form_class': EduRegistrationForm}, name='registration.views.register'),
)
As far as I remember django-registration is using function-based views, so you can not really subclass them. The approach I usually follow is "overwriting" the original views (without modifying the django-registration app of course). This works like this:
Create another app (you could call it custom_registration or whatever you want)
This app need to contain another urls.py and in your case another views.py
Copy the original register view code to your new views.py and modify it, add a pattern to your urls.py to point to this view (use the same url pattern as in django-registration for this view)
Put an include to your projects urls.py of your new app urls.py before your are including the original django-registration app. This could look like this for example:
urlpatterns = patterns('',
...
url(r'^accounts/', include('custom_registration.urls')),
url(r'^accounts/', include('registration.backends.default.urls')),
...
)
This simply works since the first matching url pattern for /accounts/register will point to your new app, so it will never try to call the one from the original app.

Categories

Resources