Receiving parameters with APIView - python

I have this routing:
url(r'^article/(?P<article_id>\d+)/', views.ArticleList.as_view())
which leads to this function:
class RSSList(APIView):
def get(self, request, *args, **kwargs):
article_id = kwargs.get('article_id')
But when I try to query something like /article/34
I get this error:
TypeError: get() got an unexpected keyword argument 'article_id'
How can I pass article_id to get()?
Thank you

You can get like this also:
def get(self, request, article_id):
print(article_id) #for >3.2
print article_id # for 2.7
If you want to make it optional:
def get(self, request, article_id=None):

Related

Django - error_403() got an unexpected keyword argument 'exception'

When the user is not allowed to see the contents of the instance, when the PermissionDenied exception was thrown, instead of forwarding it to the 404.html template, it has an error.
DetailView:
class OccurrenceDetail(OccurrenceModel, BaseDetailViewWithLogin):
permission_required = ('occurrences.see_occurrence')
def get_object(self, queryset=None):
perm = self.request.user.has_perm(self.permission_required)
obj = super(OccurrenceDetail, self).get_object(queryset=queryset)
if not perm:
raise PermissionDenied()
return obj
Urls:
handler403 = 'apps_core.core.views.error_403'
Views:
def error_403(request):
data = {}
return render(request,'errors/403.html', data)
The 403 error view expects a second argument, which is the raised exception.
To solve it, you can change your code to:
def error_403(request, exception):
...
or something more general
def error_403(request, *args, **kwargs):
...

Access request user and url parameters in django decorator

I am trying to eliminate redundant code by creating a decorator to handle simple logic that is always repeated. Basically every view I create has the following logic to check if a user is in a class.
#login_required
def view(request, class_id):
class_ = UserClasses.objects.get(user=request.user, class_id=class_id)
# if the user is in the class
if class_:
I'd like to do the following:
View:
#user_passes_test(in_class(request.user, class_id))
#login_required
def view(request, class_id):
Decorator:
from apps.classes.models import UserClasses
def in_class(request, class_id):
class_ = UserClasses.objects.get(user=request.user, class_id=class_id)
if class_:
return true
else:
return false
What's the best way to go about achieving this?
Your decorator should be like this
def user_passes_test(old_fuction):
def new_function(request, class_id, *args, **kwargs):
try:
class_ = UserClasses.objects.get(user=request.user, class_id=class_id)
except Exception as e:
return HttpResponse('ERROR: User not present in the class')
return old_fuction(request, class_id, *args, **kwargs)
return new_function
If the UserClasses contains row with both user and class_id(assumes that user is unique), the view function will be executed.Otherwise it will return an Error response(ERROR: User not present in the class).
And you view function should be
#user_passes_test
#login_required
def view(request, class_id):
if you want the class_ object in the view function, you can do it by simple changes. modify your decorator like
def user_passes_test(old_fuction):
def new_function(request, class_id, *args, **kwargs):
try:
class_ = UserClasses.objects.get(user=request.user, class_id=class_id)
except Exception as e:
return HttpResponse('ERROR: User not present in the class')
return old_fuction(request, class_id, class_, *args, **kwargs)
return new_function
And the view function should be
#user_passes_test
#login_required
def view(request, class_id, class_obj):
where class_obj contains the class_ object

custom decorator for class viewsets

I have a view set like this
class NeProjectsViewSet(viewsets.ViewSet):
def list(self, request,org_unique_id):
''' something '''
def create(self, request,org_unique_id):
''' something '''
def retrieve(self):
''' something '''
def update(self, request, pk):
''' something '''
def partial_update(self, request):
''' something '''
def destroy(self, request):
''' something '''
and i've a method like this
def check_session(self,request):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
raise ValueError('Session Expired')
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
to validate session for every request, for that i need to call this method before every method in the viewset. I read somewhere writing custom decorator is better way, so how to implement custom decorator for my view set to check session for request
Assuming you are using DRF.
I think you are going in wrong direction. If this is part of your permission layer you should just add custom permission class to your viewset
http://www.django-rest-framework.org/api-guide/permissions/
from rest_framework import permissions
class ValidateSession(permissions.BasePermission):
"""
Validate session expiration
"""
def has_permission(self, request, view):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return False
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
And then add it like this
class NeProjectsViewSet(viewsets.ViewSet):
permission_classes = (ValidateSession,)
...
Assuming you're using plain django
from django.contrib.auth.mixins import AccessMixin
class ValidateSessionMixin(AccessMixin):
"""
Validate session
"""
def has_permission(self):
current_datetime = datetime.now()
request = self.request
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return True
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
def dispatch(self, request, *args, **kwargs):
if not self.has_permission():
return self.handle_no_permission()
return super(ValidateSessionMixin, self).dispatch(request, *args, **kwargs)
And apply this mixin like this
class NeProjectsViewSet(ValidateSessionMixin, viewsets.ViewSet):
...

Django - Getting parameters from URL

I am passing the parameters in URL to my view like this:
127.0.0.1:8000/cars/?model_number=13375
and getting it like this:
class GetCarDetails(View):
def get(self, *args, **kwargs):
model_number = "";
if request.GET.get('model_number'):
model_number = request.GET.get('model_number')
But I want to pass it now like this:
127.0.0.1:8000/cars/13375/
And I want Django to treat the 13375 like model number
You need to define it at the url's:
url(r'^cars/(?P<pk>[0-9]+)/$', views.GetCarDetails.as_view(), name="getcardetails"),
And in your views:
class GetCarDetails(View):
...
def get_context_data(self, **kwargs):
context = super(GetCarDetails, self).get_context_data(**kwargs)
context["model_number"] = self.kwargs['pk'];
return context
As told by #Anentropic in comments, more detailed info here

Python decorator to check for POST parameters on Django

I have code that read like this to check if POST parameters are included on the request:
def login(request):
required_params = frozenset(('email', 'password'))
if required_params <= frozenset(request.POST):
# 'email' and 'password' are included in the POST request
# continue as normal
pass
else:
return HttpResponseBadRequest()
When the list of required POST parameters is big, this code gets messy. What I would like to do is something like:
#required_POST_params('email', 'password')
def login(request):
# 'email' and 'password' are here always!
pass
Then I'm confident that both 'email' and 'password' POST parameters are included in the request, because if not, the request would automatically return HttpResponseBadRequest().
Is there a way that Django allows me to do this, and if it doesn't, how can I do it by myself with a decorator?
You would need a custom decorator, but you can take require_http_methods as a base example:
def require_post_params(params):
def decorator(func):
#wraps(func, assigned=available_attrs(func))
def inner(request, *args, **kwargs):
if not all(param in request.POST for param in params):
return HttpResponseBadRequest()
return func(request, *args, **kwargs)
return inner
return decorator
Example usage:
#require_post_params(params=['email', 'password'])
def login(request):
# 'email' and 'password' are here always!
pass
FYI, require_http_methods source code.
i'm sharing my solution;
__author__ = 'yagmurs'
from copy import deepcopy
from rest_framework import status
from rest_framework.response import Response
def require_params(*params):
def decorator(fn):
def wrapped_function(request, *args, **kwargs):
"""
Decorator for django rest service to meet both GET and POST request
"""
error = deepcopy(REQUEST_INVALID_400)
is_param_missing = False
for param in params:
if not get_param_from_request(param, request):
error['result_message'] += param + ", "
is_param_missing = True
if is_param_missing:
error['result_message'] = error['result_message'][:-2]
return Response(error, status=status.HTTP_400_BAD_REQUEST)
else:
return fn(request, *args, **kwargs)
return wrapped_function
return decorator
def get_param_from_request(param, request):
if request.method == 'POST':
return request.data.get(param)
else:
return request.query_params.get(param)
Try with this.
Instead of require.POST(), try with require.POST('email', 'password').

Categories

Resources