I'm trying to override the render_to_response method in TemplateView to include an additional parameter for the reponse_class for the HTTP status, but having trouble using:
class ErrorView(TemplateView):
''' Inserts http status code into response '''
status = None
def render_to_response(self, context, **response_kwargs):
if self.status is None:
raise ImproperlyConfigured("ErrorView requires definition of status")
return super(ErrorView,self).render_to_response(context,{'status': self.status})
class Error404View(ErrorView):
template_name = '404.html'
status = 404
The render_to_response method (from TemplateResponseMixin) is defined with three parameters:
def render_to_response(self, context, **response_kwargs)
However, when TemplateView calls it from the get method, it only passes the context:
return self.render_to_response(context)
How can I pass response_kwargs to render_to_response?
Why not create your own ErrorTemplateView and override get method. Since you cannot reuse get method from TemplateView for your use case.
class ErrorTemplateView(TemplateView):
status = None
def get(self, request, *args, **kwargs):
if self.status is None:
raise ImproperlyConfigured("ErrorTemplateView requires definition of status")
context = self.get_context_data(**kwargs)
return self.render_to_response(context, status=self.status)
By the way if you need to customize error views, did you check this from docs?
Related
I want to create a Order and order items.
For this i am simply creating new model object in views.py using CreateApiView but i am receiving error that "Serializer_class" should be included but i don't need serializer for this.
//views.py
class CreateOrder(CreateAPIView):
def Post(self,request):
header_token = request.META.get('HTTP_AUTHORIZATION', None)
print(header_token)
access_token = header_token.split(' ')[1]
status,user = validate_token(access_token)
cart=Cart.objects.get(user=user)
print(cart)
if cart:
total=cart.total
userprofile=UserProfile.objects.get(user=user)
order,created=Order.objects.get_or_create(billing_profile=userprofile,total=total)
cart_items=CartItem.objects.get(cart=cart)
print(cart_items)
for item in cart_items:
itemid=item.item_id
qty=item.quantity
item_instance = Items.objects.get(item_id=item)
order_item,created = OrderItems.objects.get_or_create(order=order, product=item_instance,quantity=qty)
order.save()
order_item.save()
if created:
item.delete()
return Response (status=rt_status.HTTP_200_OK)
I want to understand how to achieve this with or without serializer
You are overriding the incorrect post method. If you look at the source code of CreateAPIView you will see the method named as shown below.
class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
"""
Concrete view for creating a model instance.
"""
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
NOTE: The method is all lower case.
This method calls self.create which is derived from the CreateModelMixin and this method needs a serializer.
If you need something light weight where a serializer is not needed I would suggest using APIView.
from rest_framework.views import APIView
class CreateOrder(APIView):
def post(self, request):
....
I have created a decorator 'unauthenticated_user(view_func)' in my 'decorators.py' file which restricts a user from accessing a view if the current user is not authenticated.
In the 'unauthenticated_user()' function, there is a conditional 'request.user.is_authenticated' which should return true if a user attached to the token is authenticated. However, upon testing this function, I have noticed that 'request.user' in 'decorators.py' is not always equal to the correct value returned by 'self.request.user' in 'views.py'. Instead, it often returns previously logged in users, or 'AnonymousUser' which ruins functionality.
decorators.py:
def unauthenticated_user(view_func):
def wrapper_func(request, *args, **kwargs):
if request.user.is_authenticated:
return view_func(request, *args, **kwargs)
else:
return HttpResponse('No user logged in')
return wrapper_func
views.py:
#method_decorator(unauthenticated_user, name = 'dispatch')
class UserLogout(APIView):
...
This is the views.py function I have been using to test that there is in fact an authenticated user when the decorators.py function returns 'AnonymousUser':
class Current(APIView):
def get(self, request, format = None):
try:
return Response(self.request.user.is_authenticated)
except:
return Response("no user currently logged in")
How to I ensure that 'decorators.py' 'unauthenticated_user' function has access to the user in the current request like the 'Current' view does in 'views.py'?
Any help would be much appreciated. To my knowledge there is no way to call 'self' in the 'decorators.py' function.
Thanks, Grae
Since you are using the DRF, you should make use of the IsAuthenticated permission class of the view
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
class MyAPIView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
return Response({"msg": "Some message"})
I am now learning django rest framework library. And when I read the tutorial I suddenly curious about that what will happen if client request http methods that are not defined in the view class. For example If I write the code like below
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
In this case I define the "get" and "post" methods in the View class. what if client request the "put" or "delete" methods than what happens? I read the django docs and it saids View class dispatch the http method by using dispatch(). But what is happening? Thanks in advance!
You can take a look at the source on Github. The dispatch method checks which HTTP verb was used, and calls the appropriate function, or returns 405 - Method not allowed status code when the verb is not valid/expected (http_method_not_allowed is a django built-in method in the base View class that just returns the 405 status code).
The relevant portion is pasted below:
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
Essentially the same thing is done in django's own views (dispatch in django.views.generic.View):
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
If you're ever developing with django's own view classes, "Classy Class-Based Views" is a very helpful resource.
I'm writing CreateView generic-view in my application and I want to override the render_to_response method.
I've tried to do the same thing with below code.
from edxmako.shortcuts import render_to_response as render_to_response_mako
class CreateView( generic.CreateView ):
template_name = 'cms/templates/form_bsct.html'
print dir(generic.CreateView)
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context.update({'name':'jay'})
return context
def get(self, request, *args, **kwargs):
print args
print kwargs
"""
Handles GET requests and instantiates a blank version of the form.
"""
template_name = 'cms/templates/form_bsct.html'
import os
print os.getcwd()
return render_to_response_mako(template_name)
In above code I'm trying to override the native render_to_response method with edxmako render_to_response method.
It is giving me below error.
"Cant locate template for uri %r" % uri)
TopLevelLookupException: Cant locate template for uri 'cms/templates/form_bsct.html'
It is not getting the template. Please help me how to do that?
I've got a Django Rest Framework ModelViewSet and am trying to use the TemplateHTMLRenderer to display HTML. Following along in the tutorial:
from rest_framework import permissions, renderers, viewsets
from rest_framework.decorators import link
from . import models, serializers
from .permissions import IsOwnerOrReadOnly
class SnippetViewSet(viewsets.ModelViewSet):
template_name = 'snippet-list.html'
queryset = models.Snippet.objects.all()
serializer_class = serializers.SnippetSerializer
renderer_classes = (renderers.TemplateHTMLRenderer,)
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
#link(renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
def pre_save(self, obj):
obj.owner = self.request.user
If I add a key in def resolve_context() I can access the model objects in my template that are passed into the RequestContext. If I don't add the data key then I don't know how to access the Snippets.
def resolve_context(self, data, request, response):
if response.exception:
data['status_code'] = response.status_code
#return RequestContext(request, data) # original source on github
return RequestContext(request, {'data': data}) # if I add a key I can access it
So I've got to be missing something easy or how I'm expecting this to behave is not how the authors intended?
I would go this way:
class SnippetViewSet(viewsets.ModelViewSet):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
renderer_classes = (renderers.JSONRenderer, renderers.TemplateHTMLRenderer)
def list(self, request, *args, **kwargs):
response = super(SnippetViewSet, self).list(request, *args, **kwargs)
if request.accepted_renderer.format == 'html':
return Response({'data': response.data}, template_name='home.html')
return response
and use http://127.0.0.1:8000/snippets/.html to get table (or whatever suffix you use).
This way you don't override resolver for each render type.
Other solution would be to just create dedicated view for list action and only use HTML renderer. But then you would have a small code duplication.
I also met the same question with you, and I also thought so. I came here by Google. I didn't like override "def list(self, request, *args, **kwargs):", because I felt it broke the viewset design idea. After I researched the snippet tutorial and source code in the "site-packages\rest_framework", I got the key, not viewset but "serializer.data". In the "site-packages\rest_framework\serializers.py", I found the class BaseSerializer, i.e., the top base class of ModelSerializer. Its property "data" is defined as follows:
#property
def data(self):
... # omitted the function body here, because it didn't care about this solution.
return self._data
This property data is just the "serializer.data" that is just the response passed to template. So I just overrided the data property in "snippets/serializers.py", and after calling the father's method, set the key for the returned data:
class SnippetSerializer(serializers.ModelSerializer):
#property
def data(self):
return { 'data' : super(serializers.ModelSerializer, self).data } #'data' can be replaced with other wanted name.
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
OK, use the name 'data' in your template.
I subclassed and overrode the method that provides the template context, so that the serializer data is available under data within the template context:
from rest_framework.renderers import TemplateHTMLRenderer
class MyHTMLRenderer(TemplateHTMLRenderer):
def get_template_context(self, data, renderer_context):
context = {'data': data}
response = renderer_context['response']
if response.exception:
data['status_code'] = response.status_code
return context
Inside the viewset use renderer class
renderer_classes = (renderers.JSONRenderer, renderers.TemplateHTMLRenderer)
like above and override the ListModelMixin's list method.
mariodev's answer gives the best example also.