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):
...
Related
I'm trying to test my search results to check the response when there are no results.
this is the function in my view:
def get_context_data(self, *args, **kwargs):
result = super().get_context_data(**kwargs)
query = self.request.GET.get('q')
result['book'] = get_object_or_404(books,ISBN = query)
return result
this is my test class and function
class Test_Search_results_view(TestCase):
def test_no_results(self):
response1 = self.client.get('/TextSearch/results1/?books=new&q=9780815345244')
response2 = self.client.get('/TextSearch/results2/?books=new&author=Bruce+Alberts&Book+Name=Molecular+Biology+of+the+Cell&edition=6')
self.assertEqual(response1.status_code, 404)
self.assertEqual(response2.status_code, 404)
self.assertQuerysetEqual(response2.context['book'],[])
but i keep getting this error
self.assertQuerysetEqual(response2.context['book'],[])
File "C:----\context.py", line 83, in __getitem__
raise KeyError(key)
KeyError: 'book'
how do I check if my book query got empty results?
If this line: result['book'] = get_object_or_404(books,ISBN = query) causes 404 to be raised, then, you will have nothing in result['book']. Because the 404 is and exception which is raised. get_object_or_404 does not return an empty value which you could assert in your test.
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):
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
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').
I am writing an app in django rest-framework:
My views.py:
class tagList(generics.ListCreateAPIView,APIView):
model = tags
serializer_class = getAllTagsDetailSerializer
def get_queryset(self):
print "q1"
print self.request.QUERY_PARAMS.get('tag', None)
print self.request.user
print "q1"
if tags.objects.filter(tag='burger')!= None:
return tags.objects.filter(tag='burger')
else:
content = {'please move along': 'nothing to see here'}
return Response(content, status=status.HTTP_404_NOT_FOUND)
I want to return error status code if query returns None.
But the problem if i try to set Response it throws error:
Exception Type: TypeError
Exception Value:
object of type 'Response' has no len()
Exception Location: /usr/local/lib/python2.7/dist-packages/django/core/paginator.py in _get_count, line 53
Else if query result is Not None it is working.
How can i set status code on Django rest-framework.
The method is expected to return a QuerySet, not a Response object, my bet is that you should throw an Exception, either an APIException or an Http404.
Anyway your handling seems odd, I think you should just return the QuerySet and the framework will handle if the result is empty or not. The method should look like this:
def get_queryset(self):
return tags.objects.filter(tag='burger')
Can you try this
model = tags # Model name
serializer_class = getAllTagsDetailSerializer # Call serializer
def get_queryset(self):
key = self.request.QUERY_PARAMS.get('appKey', None)
getTagName = self.request.QUERY_PARAMS.get('tagName')
keyData = app.objects.filter(appKey=key).exists()
try:
if keyData == True:
return tags.objects.filter(tag=getTagName)
else:
raise exceptions.PermissionDenied
except app.DoesNotExist:
pass
I think it will work....