Parsing POST request - object() takes no parameters - django

I try to access post request and check if user with email that is in post request already exist. When I try to send data to endpoint, I get error
TypeError: object() takes no parameters
my views.py
#csrf_exempt
class CheckIfEmailAvailable():
#csrf_exempt
def check(request):
email = request.POST.get("email")
if User.objects.filter(email=email).exists():
return Response({'status': 'not available'})
my url.py
url(r'^api/checkmail/', CheckIfEmailAvailable, name='check'),
What am I doing wrong ?

In this case better to use function in the url
from your_app.views import check
url(r'^api/checkmail/', check, name='check')
and your view will be like this (only function)
#csrf_exempt
def check(request):
email = request.POST.get("email")
if User.objects.filter(email=email).exists():
return JsonResponse({'status': 'not available'})
Also FYI if you want to use #csrf_exempt with classes you should use dispatch, you can get more info here
Example of JsonResponse
from django.http import JsonResponse
def your_view(request):
return JsonResponse({'foo':'bar'})

You need to inherit your class your generic django views for this to work. Url patterns expect a callable that can accept request (with args and kwargs) and return response. View.as_view class method returns a callable for you.
# In views file
from django.views.generic import View
...
class CheckIfEmailAvailable(View):
def get(self, request, *args, **kwargs):
return self.check(request) # or something else depends on your use case
# In urls file
from django.views.decorators.csrf import csrf_exempt
...
url(r'^api/checkmail/', csrf_exempt(CheckIfEmailAvailable.as_view()), name='check'),
Moreover csrf_exempt decorator won't work (out of box) on classes, neither on bound methods for that matter. Better way should be to use them in urls.

If you had posted the full traceback, you would see that the error does not come from parsing the request; Django does not even get nearly that far.
You can't use a class as a view like that. You should have check as a standalone function, without a class, and refer to it directly in your urls.
Django does support class-based views, but they have a very specific structure, need to inherit from the proper base class, and be referenced in the urls.py in a specific way.

Related

How to check if current url in list of urlpatterns?

I am a bit puzzled. I want to check if the current url of the website is in a specific subset of my urlpatters. Which function of django would do this? This is for a middleware that requests additional information before moving to a specific part of my website.
class AuthorityMiddleware(object):
def process_request(self, request):
current_url = request.path_info
if not request.user.is_anonymous() and current_url not in exclude_list:
if not request.session.get('authority'):
return get_the_authority(request)
How should exclude list relate to the urlpatterns defined in urls.py?
Ok, my issue basically is the result of bad design. The whole issue can be solved if I use decorators to ask for the authority for the views that require it. Back when I wrote the above code I was thinking that middlewares would be the only place to redirect and call further functions before a view is shown, but in fact they are good to apply a function to all your views. Decorators are better if the functions only apply to a subset of views.
from django.core.urlresolvers import reverse, resolve
from django.http import HttpResponseRedirect
def project_required(func):
def decorated(request, *args, **kwargs):
if not request.session.get('authority'):
request.session['previous_url'] = resolve(request.path_info).url_name
return HttpResponseRedirect(reverse('project_login'))
return func(request, *args, **kwargs)
return decorated

Redirect anonymous users to log in (don't show them anything)

Django 1.9.6.
I want to absolutely disable the whole website from viewing by anonymous users. Anonymous users will always be redirected to login page.
I have created a general view. The problem is that subclasses of GeneralView may not just render a template but perform some calculations or just be of different kinds: DetailView, ListView etc.
class GeneralView(View):
def get(self, request, template):
if not request.user.is_authenticated() and request.user.is_active:
return redirect("auth_login")
else:
return render(request, template)
If I try to inherit, the code gets clumsy:
class HomePageView(GeneralView):
def get(self, request, template):
super().get(self, request)
Well, what can I do here? I get error message that my get method doesn't return HttpResponse.
I can rewrite get method of the superclass to return status code. Then check it in the subclass. But this seems to be garbage.
In other words I'm lost in clouds of inheritance. Could you give me a kick here how always to redirect anonymous users to login page, whereas let logged in users see everything.
Thank you in advance.
You could use the UserPassesTestMixin for this.
from django.core.urlresolvers import reverse_lazy
class GeneralView(UserPassesTestMixin, View):
def test_func(self):
# I assume you missed out the brackets in your question and actually wanted 'if not (request.user.is_authenticated() and request.user.is_active)'
return request.user.is_authenticated() and request.user.is_active
login_url = reverse_lazy('auth_login')
The mixin overrides dispatch, so you won't have to call super() when you override get() in your view.
class HomePageView(GeneralView):
def get(self, request):
...
I think your error for get method not returning belongs to not putting a return statement. in fact, in get method of the child class you should do:
class HomePageView(GeneralView):
def get(self, request, template):
return super().get(self, request)
That should solve the error
If you have lots of views and you do not want to touch any one you can just use Middleware for this issue. Try code below:
import traceback
from django.contrib.auth.decorators import login_required
class RejectAnonymousUsersMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
current_route_name = resolve(request.path_info).url_name
if current_route_name in settings.AUTH_EXEMPT_ROUTES:
return
if request.user.is_authenticated:
return
return login_required(view_func)(request, *view_args, **view_kwargs)
Cautions:
You must add this middleware to the bottommost of middleware section
of settings.py
You should put this variable in settings.py
AUTH_EXEMPT_ROUTES = ('register', 'login', 'forgot-password')
New versions of Django provides the #login_required decorator. If an anonymous user tries to access the view, the system redirects to the login page.
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
It can be used in function views, as shown above, or generic views (using #method_decorator, usually in dispatch method)
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
#method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'

Is there a way to prettify name of detail_route when using url_path?

Project makes use of Django REST Framework. Here is one of detail views:
#detail_route(methods=['POST'],
permission_classes=[IsAuthenticated],
url_path="invite/(?P<member_id>[^/.]+)")
def invite_member(self, request, pk=None, member_id=None):
...
When opening browser i see that this url specified as follows:
^api/ ^deal/ ^ ^deals/(?P<pk>[^/.]+)/invite/(?P<member_id>[^/.]+)/$ [name='deal-invite/(?P<member-id>[^/.]+)']
As you can see name for this view looks awfully - is there a way to make it prettier?
If you do not want to use the default name generated for your custom action, you can use the url_name parameter to customize it.
For example, if you want to change the name of our custom action to 'user-change-password', you could write:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route
class UserViewSet(ModelViewSet):
...
#detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password')
def set_password(self, request, pk=None):
...

Adding more views to a Router or viewset (Django-Rest-Framework)

Essentially, I'm trying to find a good way to attach more views to a Router without creating a custom Router. What's a good way to accomplish this?
Here is something sort of equivalent to what I'm trying to accomplish. Variable names have been changed and the example method I want to introduce is extremely simplified for the sake of this question.
Router:
router = routers.SimpleRouter(trailing_slash=False)
router.register(r'myobjects', MyObjectViewSet, base_name='myobjects')
urlpatterns = router.urls
ViewSet
class MyObjectsViewSet(viewsets.ViewSet):
""" Provides API Methods to manage MyObjects. """
def list(self, request):
""" Returns a list of MyObjects. """
data = get_list_of_myobjects()
return Response(data)
def retrieve(self, request, pk):
""" Returns a single MyObject. """
data = fetch_my_object(pk)
return Response(data)
def destroy(self, request, pk):
""" Deletes a single MyObject. """
fetch_my_object_and_delete(pk)
return Response()
One example of another method type I need to include. (There are many of these):
def get_locations(self, request):
""" Returns a list of location objects somehow related to MyObject """
locations = calculate_something()
return Response(locations)
The end-result is that the following URL would work correctly and be implemented 'cleanly'.
GET example.com/myobjects/123/locations
The answer given by mariodev above is correct, as long as you're only looking to make GET requests.
If you want to POST to a function you're appending to a ViewSet, you need to use the action decorator:
from rest_framework.decorators import action, link
from rest_framework.response import Response
class MyObjectsViewSet(viewsets.ViewSet):
# For GET Requests
#link()
def get_locations(self, request):
""" Returns a list of location objects somehow related to MyObject """
locations = calculate_something()
return Response(locations)
# For POST Requests
#action()
def update_location(self, request, pk):
""" Updates the object identified by the pk """
location = self.get_object()
location.field = update_location_field() # your custom code
location.save()
# ...create a serializer and return with updated data...
Then you would POST to a URL formatted like:
/myobjects/123/update_location/
http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing has more information if you're interested!
You can now do this with the list_route and detail_route decorators: http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing
For example:
from rest_framework.decorators import list_route
from rest_framework.response import Response
...
class MyObjectsViewSet(viewsets.ViewSet):
...
#list_route()
def locations(self, request):
queryset = get_locations()
serializer = LocationSerializer(queryset, many=True)
return Response(serializer.data)
You define method like you do now, but you need to use the same url as method name and add link decorator, so for
/myobjects/123/locations/
You add method like this
#link(permission_classes=[...])
def locations(self, request, pk=None):
...
and router will pick it automatically.
From Routing to extra methods on a ViewSet:
I think you may need to route the method by hand, i.e. The Old-Fashioned Way™.
First pull the method out as a separate view:
set_password_view = UserViewSet.as_view({'post': 'set_password'})
(or such)
Then assign your URL:
url(r'^users/username_available/$', set_password_view, name-=...)
(Or such)
There's a related question on SO.
If you want to extend a viewset with a view that is or should not directly be written inside your viewset, you can write a “wrapper” action to pass the data through.
For example, with class based views:
from somewhere import YourExternalClassView
class SomeViewSet(viewsets.ReadOnlyModelViewSet):
# ...
#action(detail=True)
def your_action(self, request, pk):
return YourExternalClassView.as_view()(request, pk=pk)
How does it work?
On class based views, the as_view method returns a view function, to which we will pass the data we received from the action. The view will then hand over to process further.
For non-class based view, the views can be called/wrapped directly without .as_view(...)(...).

Django: How can i get the logged user outside of view request?

I have a class method (outside of a view) who needs the logged user's information. How can i retrieve the logged in user without passing the request to the method? Unfortunately i can't find nowhere a nice solution and it's not logical just not exist such a way to do it, because Django should store somewhere the logged in user. Otherwise (i believe) it would be impossible to use #login_required decorator from django.contrib.auth.decorators. Right?
So if it's not possible why it's not? Why Django works like this if the only think i want is the logged in user and not all the informations inside request?
Thanks in advance.
About decorators, it is wrong. Actually decorators called with request argument.
I believe better way is that passing user or request object to class's method. But there are other ways to access request.
Here is the code that we use. You need to add this middleware to MIDDLEWARES. And import & calling get_request function.
Update July 2017: Tested with Python 3.6.1 and Django 1.10.7, based in the original code from this answer and in the Writing your own middleware documentation.
First create a new app, ie. startapp request_middleware.
Then add "request_middleware" to your INSTALLED_APPS in settings.py.
After that paste the code bellow in, ie. request_middleware.middleware.py.
Finally add "request_middleware.middleware.RequestMiddleware" to your MIDDLEWARE in settings.py (In my case I've placed it in between 'debug_toolbar.middleware.DebugToolbarMiddleware' and 'django.middleware.security.SecurityMiddleware' as far above the list as I could).
# request_middleware.middleware.py
from threading import current_thread
_REQUESTS = {}
class RequestNotFound(Exception):
def __init__(self, message):
self.message = message
def get_request():
thread = current_thread()
if thread not in _REQUESTS:
raise RequestNotFound('global request error')
else:
return _REQUESTS[thread]
class RequestMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def process_request(self, request):
_REQUESTS[current_thread()] = request
def __call__(self, request):
self.process_request(request)
response = self.get_response(request)
return response
After that simply do from request_middleware.middleware import get_request in order to use get_request in your code.