I was trying out logging all URLs accessed by user along with user id and date time when it was accessed using django middleware as explained here.
For some URLs it was not logging user id. I checked and found that the request.user.username was empty string. I checked views corresponding to those URL and found that those views did not have desired decorators. For example, I changed this:
def getXyz_forListView(request):
# view body ...
to this:
#api_view(['GET'])
#authentication_classes([TokenAuthentication,])
def getXyz_forListView(request):
# view body ...
and it started working.
However some views are created from classes:
class XyzView(View):
def get(self, request):
# view body ...
I added same decorators:
class XyzView(View):
#api_view(['GET'])
#authentication_classes([TokenAuthentication,])
def get(self, request):
# view body ...
But it is still not working. What I am missing?
PS:
It is added to urls.py as follows:
urlpatterns = [
# ...
url(r'^xyz/', XyzView.as_view(), name="xyz"),
]
I think you should try to inherit from APIView class:
from rest_framework.views import APIView
Related
I have this views.py where I've implemented Class based views, but let's say I want to call a function get_featured_products when the url is https://localhost:8000/featured_products. What sould my urls.py look like to call the get_features_products function?
from django.shortcuts import render
from rest_framework import views
from rest_framework.response import Response
from .models import *
from .serializers import *
# Create your views here.
class ProductView(views.APIView):
model= Product
serializer = ProductSerializer
def get(self,request):
qs = self.model.objects.all()
serializer = self.serializer(qs, many=True)
return Response(serializer.data)
def post(self,request):
serializer = self.serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.error_messages())
def put(self,request,pk):
product = Product.objects.get(id=pk)
serializer = self.serializer(instance=product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.error_messages)
def get_featured_products(self,request):
#some code here
return None
How should I refer to get_featured_products in my urls.py
You can list it as any other class-based view in your urls.py using .as_view() but you will always have to have queryset as a class variable in your class that inherits from views.APIView.
Your view has to be defined like this
class ProductView(APIView):
queryset = Product.objects.all() # Here put your own queryset, for me if I dont i get error
def get(self, request):
print("GET REQUEST")
return Response({"hello" : "world"})
# you can similarly define other methods such as post, put like you already have
And then in your urls.py
urlpatterns = [
path('admin/', admin.site.urls),
# You'll obviously have to import it if it is not in the same file
path('featured_products', ProductView.as_view())
]
For any class-based view, the urls.py can only contain ProductView.as_view(). It is not possible to directly refer to a method within a class.
as_view() function calls an instance of the class and returns a response based on the following methods:'get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'
If your method doesn't match the above, as is the case, you will get a HTTPresponseNotAllowed error.
You may place the method within one of the allowed methods and make it run.
You may check this link to know more: https://djangodeconstructed.com/2020/01/03/mental-models-for-class-based-views/
You can make the method as static and refer to this method from urls.py as:
# views.py
class ProductView(views.APIView):
#staticmethod
def get_featured_products(request):
#some code here
return None
# urls.py
urlpatterns = [
path('featured_products', ProductView.get_featured_products)
]
I've always written data into database when posting via Django Rest Framework endpoints. This time I would like to process received data and send it somewhere else without writing into DB. I switched from ModelViewSet to ViewSet, I can issue GET request OK but receiving Bad Request 400 when I curl or POST via DRF URL. Here's a working minimal code (removed need for authentication etc):
urls.py
from django.urls import path, include
from .views import ContactView
from rest_framework import routers
router = routers.DefaultRouter()
router.register('message', ContactView, basename='message')
urlpatterns = [
path('', include(router.urls)),
]
serializers.py
from rest_framework import serializers
class ContactSerializer(serializers.Serializer):
text = serializers.CharField(max_length=250)
views.py
from rest_framework.response import Response
from .serializers import ContactSerializer
from rest_framework import viewsets
class ContactView(viewsets.ViewSet):
def list(self, request):
return Response('Got it')
def create(self, request):
serializer = ContactSerializer(data=request.data)
if serializer.is_valid():
return Response(serializer.data)
else:
return Response('Invalid')
Would greatly appreciate your suggestions.
You can use GenericAPIView for get or post request and do some logic in validate method, for example do something with signals or edit something. Also u can use #detailt_route or #list_route for any ModelViewSet for write special url for instance, example for edit extra data.
how i did rarely:
in urls.py
urlpatterns = [
url('v1/message', ContactAPIView.as_view(), name='message'),
]
in view.py
class ContactAPIView(GenericAPIView):
serializer_class = ContactSerializer
permission_classes = ()
def post(self, request, *args, **kwargs):
serializer_class = self.get_serializer_class()
serializer = serializer_class(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
data = {"status": True}
return Response(data)
in serializers.py
class ContactSerializer(serializers.Serializer):
text = serializers.TextField()
def validate(self, attrs):
write some logic
you are getting this error because you are using Viewsets which uses DefaultRouter to register routers for you. What it does is that it creates 2 urls for your viewset
message
message/id
so in your current case; i.e. viewset you need to send some dummy number in your url to access this post function (which is not a good approach).
So, you should use any class which parent doesn't include ViewSetMixin (which gives functionality of Router Registration) like in your case inherit your view from these classes
ListModelMixin
CreateModelMixin
GenericAPIView
I am creating a small web application as a mini project of mine to learn the Django framework. I'm on Version 1.9.4, on OS X. I'm trying to pass a string in the URL that will be sent to a class-based view, and it will return a different template based on the URL. To my knowledge, doing (?P) will allow the input of dynamic text. \w is for characters, and writing <name> will pass it as a variable. Is this configured right, or is this is not the correct way to do it?
The reason I'm concerned is that the Django documentation uses method views, while I am using class-based views.
urls.py
from django.conf.urls import url
from . import views
app_name = 'xyz'
urlpatterns = [
url(r'^create/(?P<ty>\w+)$', views.ArticleView.as_view(), name='article-form'), #.as_view() to turn Class into View
]
views.py
class ArticleCreate(View):
l = {
'weapon': WeaponForm,
'map': MapForm,
'operator': OperatorForm,
'gadget': GadgetForm,
'skin': SkinForm
}
ty = ty.lower()
template_name = 'xyz/create_article_form.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
pass
The arguments that are being passed to the url should be "catched" within the view inside the relevant function, for example:
def get(self, request, ty):
ty = ty.lower()
return render(request, self.template_name)
I am trying to create a restful api using class based views in django.
class SomeAPI(MultiDetailView):
def get(self,request,format=None):
#some logic
def post(self,request,format=None):
#some logic
I want to process a get request like www.pathtowebsite.com/api?var1=<someval>&var2=<someval>&var3=<someval>
My post url would be www.pathtowebsite.com/api/unique_token=<token_id>
Basically a get request would generate a unique token based on some parameters and a post request would post using that token.
How would my URL file look like in such a scenario?
P.S I have hardly ever worked with class based views.
First of all: DRF will do a lot of your legwork for you, even generate consistent URLs across your API. If you want to learn how to do things like this in the Django URL dispatcher then you can embed regexes in your URLS:
project/urls.py:
from django.conf.urls import url
from project.app.views import SprocketView
urlpatterns = [
url(r'^api/obj_name/(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
url(r'^api/obj_name/unique_token=(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
]
project/app/views.py
from django.shortcuts import get_object_or_404
from django.views.generic import View
from .forms import SprocketForm
from .models import Sprocket
class SprocketView(View):
def get(request, id):
object = get_object_or_404(Sprocket, pk=id)
return render(request, "sprocket.html", {'object':object}
def post(request, id):
object = Sprocket.get_or_create(pk=id)
object = SprocketForm(request.POST, initial=object).save(commit=False)
object.user = request.user
object.save()
return render(request, "sprocket.html", {'object':object, 'saved':True})
That's a lof of functionality that frameworks are supposed to lift from you and I suggest reading about Django CBV. One resource I can wholeheartedly recommend is Two Scoops.
I have a view that puts some context and renders the template from this context. I want view display all the things if no search query is there, and show searhed things, if anything searched.
class MyCurrentView(View):
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response("mytemp.html", ..
urls.py:
url(r'^search/$', MyCurrentView.as_view())
Now, I am integrating this with SEarchView like this:
class MyCurrentView(SearchView): (If u observe, I subclassed SEarchView).
template = 'mytemp.html'
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response...
def get_context_data(self, ...):
print "....this should print" #But not printing. So, unable to add data
return data
urls.py:
url(r'^search/$', MyCurrentView.as_view())
# as_view() gave me error, so I did MyCurrentView() , may be thats y, get_context_data not calling.
Will provide more information if necessary.
New Django-style class based views were added via PR #1130 to django-haystack:
https://github.com/toastdriven/django-haystack/pull/1130
You can now use search views like you normally would with django (see changes in pull request).
from haystack.generic_views import SearchView
class MySearchView(SearchView):
def get_context_data(self, **kwargs):
# do whatever you want to context