Django rest framework creating Orders and order items - django

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):
....

Related

Django overriding detail view get method

This is my post detail view and it works perfectly.
class PostDetailView(DetailView):
model = Post
context_object_name = 'post'
template_name = 'posts/detail.html'
def get_queryset(self, *args, **kwargs):
request = self.request
pk = self.kwargs.get('pk')
queryset = Post.objects.filter(pk=pk)
return queryset
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
content['comments'] = Comment.objects.all()
return context
However, when I add get method to the view it does not work anymore.
def get(self, request, *args, **kwargs):
# how to return here so that it works exactly like before
After adding get method get_queryset and get_context_data do not gets called automatically and the context is empty in the template. So what would be the get method so that it works exactly like before?
EDIT
My target is to do something like this
if request.is_ajax():
html = render_to_string('comments/detail.html') # ajax reply with html data
return HttpResponse(html)
return render 'posts/detail.html'
So where do I put this code and still want to keep call all methods such as get_queryset and get_context_data to be called automatically?
The idea of views like a DetailView, ListView, etc. is that it implements the boilerplate logic for you. So it has defined a function def get(self, request, *args, **kwargs) that is used to render the logic. You can usually tweak a few things by specifying the model, queryset, etc. without reimplementing the entire view.
For a DetailView [Django-doc], the logic is implemented in the BaseDetailView you can inspect the source code [GitHub]:
class BaseDetailView(SingleObjectMixin, View):
"""A base view for displaying a single object."""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
One general piece of advice I want to share:
Before overriding any attribute, one must have deep knowledge of what is the significance of that attribute (callable or not callable). This advice applies to any language or framework. Suppose when someone overrides the get in Django, all the methods that are being called from get will not be invoked unless one invokes that from overridden get. So you should see the source of get and observe that methods are called from that.

are there any way to aggregate multiple API result into single API in Django Rest Framework?

I have following URL set which returns JSON API. Now I wonder is there any way to create another API which aggregates all of these API results and return to one ajax call from client side lets say,url(r'^api/allData/(?P<pk>\d+)$',allData.as_view())
Does anyone know how to prepare class in views.py to achieve this?
urlpatterns = [
url(r'^api/envelope/(?P<pk>\d+)$',envelopeData.as_view(),name='api-envelope'),
url(r'^api/glass/(?P<pk>\d+)$',glassData.as_view(),name='api-glass'),
url(r'^api/opaque/(?P<pk>\d+)$',opaqueData.as_view(),name='api-opaque'),
url(r'^api/plant/(?P<pk>\d+)$',plantData.as_view(),name='api-plant'),
url(r'^api/fan/(?P<pk>\d+)$',fanData.as_view(),name='api-fan'),
url(r'^api/pump/(?P<pk>\d+)$',pumpData.as_view(),name='api-pump'),
url(r'^api/people/(?P<pk>\d+)$',peopleData.as_view(),name='api-people'),
url(r'^api/light/(?P<pk>\d+)$',lightData.as_view(),name='api-light'),
url(r'^api/smallpower/(?P<pk>\d+)$',spData.as_view(),name='api-sp'),
]
Seems like you are using APIView. So, You could call the get() post() methods of the view by using their class object.
Here is one Example
from rest_framework.views import APIView
from rest_framework.response import Response
class MyView_One(APIView):
def get(self, request, pk, *args, **kwargs):
return Response(data={"message": self.__class__.__name__})
class MyView_Two(APIView):
def get(self, request, pk, *args, **kwargs):
return Response(data={"message": self.__class__.__name__})
class MyView_Three(APIView):
def get(self, request, pk, *args, **kwargs):
return Response(data={"message": self.__class__.__name__})
class My_All_View(APIView):
def get(self, request, pk, *args, **kwargs):
return_data = {}
one = MyView_One()
return_data.update({"one": one.get(request, pk).data})
two = MyView_Two()
return_data.update({"two": two.get(request, pk).data})
three = MyView_Three()
return_data.update({"three": three.get(request, pk).data}
return Response(data=return_data)
Use this My_All_View in your urls.py as any other views
Screenshot
You can use nested serializer, for example:
class Serializer1(Serializer):
...
class Serializer2(Serializer):
....
class Serializer3(Serializer):
serializer1 = Serializer1()
serializer2 = Serializer2()
class Meta:
fields = ('serializer1', 'serializer2')
But about merging views, I do not think.

How do I get the current user for my created_by field in Django 1.9?

I'm trying to pull the session user into my model's save() method. The docs for HttpRequest and all the examples I've found assume you already have the object instanciated, but I can't seem to find a method that will do the instanciation.
I'm thinking I should be using HttpRequest.user , but I don't know how to generate the instance in my model so I can actually do it.
Here's my save() override. It generates type object 'HttpRequest' has no attribute 'user', but considering this is a class and not an object reference that isn't really surprising.:
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not hasattr(self, 'id'):
self.date_created = timezone.now()
self.created_by = HttpRequest.user
self.last_updated_date = timezone.now()
self.last_updated_by = HttpRequest.user
super(Caregiver, self).save(*args, **kwargs)
views.py added for more info
class CaregiverCreateView(CreateView):
template_name = 'single_form_generic.html'
model = Caregiver
form_class = CaregiverCreateForm
django-cuser can do this easily. This library adds middleware that can be called in a view, model method, etc to get the current user. If you are ok with the user being assigned at the model's save method, then you just need to call the middleware to inspect the session as below.
Once set up, it can be called like this:
from cuser.middleware import CuserMiddleware
class YourModel(models.Model):
def save(self, *args, **kwargs):
self.created_by = CuserMiddleware.get_user()
super(YourModel,self).save(*args, **kwargs)
If you are calling save() explicitly, you could pass the user instance directly to the method:
def save(self, user, *args, **kwargs):
# use the user
Then when you call it in views.py, do:
instance.save(request.user)
I had to dig around a little, but I did end up finding an answer for you future googlers:
The class based view docs actually have a relevant example. Since the view already has access to the request and the form and model are tied, you really only need to inject it in the view submission by overriding the form_valid method there.
def form_valid(self, form):
form.instance.created_by = self.request.user
form.instance.last_updated_by = self.request.user
return super(CaregiverCreateView, self).form_valid(form)

how to make a get request to a url inside django view and return the response?

without using serializer_class and queryset properties inside viewclass(which inherits viewsets.ModelViewSet) ;
i want to make a get request to a another url and return its response as the result of django get request.
can we do that?
Thanks.
You can put any dummy model and make it work.
class SampleViewSet(APIView):
model = DummyModel
renderer_classes = (JSONRenderer,)
def get(self, request, *args, **kwargs):
if request.method == "GET":
// do some operation
return Response(<json response>, status=status.HTTP_200_OK)

How do you access data in the template when using DRF ModelViewSet and TemplateHTMLRenderer?

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.