So, I have a view that inherits from APIView, I've defined get, post and delete methods.
My urls.py:
path('projects/', projects.ProjectView.as_view()),
path('projects/create/', projects.ProjectsView.as_view()
But right now I can make a request with any method accessing these API's. For example, I can create a project going to 'projects/' and I can delete a project going to 'projects/create/'.
Is there a way to specify what methods I wanna use for a specific url? When a user goes to 'projects/' I want only the 'get' method to be allowed for this url.
On classy way to do it is to inherit from generic-view
Your ProjectView should inherit from RetrieveAPIView and ProjectsVIew from CreateAPIView
And you could probably rename your views to something more explicit.
Related
I am learning Django out of pure passion and I seem to have trouble understanding some core principles of Django that really give me headackes and i tried searching online and reading the docs but i don't seem to fully understand. I'll just simply shoot the questions and try to be clear . I apologise for anything stupid I say . I am just trying to get my knowledge straight.
1. What is a "request"?
OK, so I am thinking of a GET request for a webpage but online i see python code like self.request.user.is_superuser and i am thinking of an User object fetched and displayed to the template to which i can apply User methods. It is clearly more to this request than i already know.
2. CBV's built in methods. The get methods. How do they execute? In what order.
I noticed programmers override these methods sometime . If i redefine more than one method in a CBV i start getting weird behaviour.
For example if i declare and redefine 2 methods in a Detail View get_object() and get_queryset() which of them will be executed first after calling the view? Being a method it should be called somehow in order to execute but i don't know the order how these methods are called for a CBV if there is more than one. Probably i should only define one of them, not both.
3. Queryset. Is it a list?
I have an ideea what querysets are and that you can apply filters to them but what do they return? Do they return objects of the model i am querying?.
OK so, if i have a DetailView CBV and override the get_queryset() method will this return on object and pass it to my template?. Here I am using a filter but what if am not using a filter. What will the CBV return? Will it return the entire set of objects?
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
def get_queryset(self, *args, **kwargs):
qs = super().get_queryset(*args, **kwargs)
if not self.request.user.is_superuser:
qs = qs.filter(pk=self.request.user.pk)
return qs
4. Can you kindly recommend a Udemy course, video course or book where querysets, CBV methods and ORM are explained clearly?
Preferably video cause it makes so much difference when i see the code working
The thing is I understood how the MVT mechanism works but these class built in methods and overriding them gives me a lot of problems . I never encountered them before and when i start using them I feel like as if i am walking in the dark .
Sorry for the long post.
Thanks
What is a request?
It is a HttpRequest object [Django-doc]. This is an object that contains data about the request the client made to the server. For example this contains an attribute .method [Django-doc] that contains a string like 'GET', 'POST', 'PATCH', etc. that specifies the request method used.
but online i see python code like self.request.user.is_superuser and I am thinking of an User object fetched and displayed to the template to which I can apply User methods.
One can install middleware [Django-doc], this is tooling that pre-processes the request, or post-processes the response. Normally the AuthenticationMiddleware [Django-doc] is added in the settings.py file by default. This will add an extra attribute .user to the request that lazily loads the user that has been logged in. If you would remove this middleware, the .user attribute will no longer exist.
CBV's built in methods. The get methods. How do they execute? In what order.
That depends on the specific class-based view. The documentation however specifies how most methods are performed. For example for a ListView [Django-doc], the documentation mentions the method flowchart:
Method Flowchart
setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_queryset()
get_context_object_name()
get_context_data()
get()
render_to_response()
It also links to the methods that explain what these are doing.
In essence, each class-based view can have methods like get, post, put, patch, etc. Based on the method of the request, the request is dispatched to the method with the same name.
Queryset. Is it a list?
No. A QuerySet is an object that more or less represents a query that you can perform on the database. QuerySets are lazy. That means that as long as you do not iterate over them or for example call len(…) over these, they will not make that query. If you iterate, etc. over these, they will make a query to the database, and then you iterate over the result of the query. The results are normally wrapped in model objects (unless you use functions like values(…) [Django-doc] or values_list(…) [Django-doc].
Can you kindly recommend a Udemy course, video course or book where querysets, CBV methods and ORM are explained clearly?
It might help to start with the Django tutorials. These go step-by-step over the architecture of Django. The documentation on the QuerySet API explains how you can make querysets. The page on Query expressions gives examples on how to make more advanced queries. Finally the Django documentation also has a page on class-based views.
I'm trying to make my function based rest framework views which use the #api_view decorator with the Django OAuth Rest Framework Toolkit, where I'm using TokenHasScope as the permission_class. However, this needs a mandatory attribute called required_scopes but I'm not sure how I can get this specified in a function based views?
Not exactly what you asked for, but an alternative to using Viewsets could be defining a view that subclass ScopedProtectedResourceView and set the scopes with the required_scopes attribute.
You can create a view that subclasses TokenHasScope then hardcode get_scopes method to return the scopes you want. If the scopes change across different view, you can create a decorator which takes in a list of scopes and passes it on, then set your get_scopes method to pick up the scopes from that decorator.
What are the differences between the APIView and ViewSets classes? I am following Django REST-framework official documentation. I find it lacking in examples.
Can you explain the above difference with a suitable example?
APIView is the most basic class that you usually override when defining your REST view. You usually define your methods like get, put, delete and others see: http://www.cdrf.co/3.5/rest_framework.views/APIView.html. With APIView you define your view and add it to your urls like so:
# in views.py
class MyAPIView(APIView):
... #here you put your logic check methods you can use
# in urls.py
url(r'^posts$', MyAPIView.as_view()), #List of all the posts
Because certain things like getting /post/4, deleting /post/4, getting all posts, updating posts, and creating new posts are so common DRF provides ViewSets.
Before you use ViewSets, let me tell you about Generic Classes. They things very well, but you need to provide the full API end point like I did with my MyAPIView view (again for more info check http://www.cdrf.co/ or http://www.django-rest-framework.org/). So you would have to define your own urls path.
But with ViewSets you create ViewSet that actually merges all the above described operations and also you don't need to define the url path you, instead you use a router that makes paths for you like this:
# views.py
class PostViewSet(ViewSet): # here you subclass ViewSet check methods you can override, you have also ModelViewSet,...
# urls.py
router = routers.DefaultRouter()
router.register(r'post', PostViewSet, base_name='Post')
APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc.
Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.
Viewsets are also used to write logic to perform standard database operations and to interface with a database back-end. And are usually used for existing database model to manage predefined objects.
The functions you add to the APIView are different than the functions you add to the ViewSet class.
APIView: you add functions for the particular HTTP method you want to support on your endpoint. Ex: GET, POST, PUT, PATCH, DELETE
ViewSet: you would add functions that represent actions that you'd perform on a typical API. Ex: LIST, CREATE, RETRIEVE, UPDATE
Viewsets and APIView both allow us to write logic for end point but Viewsets dont define functions which map to HTTP methods instead map to common API object actions
I'm converting some django views to be class based, and so far loving the flexibility.
Most of my views subclass from a parent view ClubView. Each subclassed view that needs to handle a post() method override needs to have access to the corresponding club value.
This value is in the URL, so the request variable has it. However, is there a way for me to grab this value, and fetch the corresponding club object outside of the post() method? like a pre-post() method or something. Mainly because I don't want to copy/paste club = Club.objects.get(...
A more general question -- in what order do all the methods execute in? Django's documentation on this seems lacking.
This DjangoProject page on Generic Display Views seems to be the most helpful, imo.
It covers both ListView and DetailView and explains in detail the methods executed in a class-based display view -- Here's an example of DetailView methods called:
setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_slug_field()
get_queryset()
get_object()
get_context_object_name()
get_context_data()
get()
render_to_response()
Actually, you're really doing it upside down. Instead of a central ClubView, it's more flexible to have one view class for each of the individual actions/pages. E.g., you might have something like this:
class ClubListView(ListView):
model = Club
class ClubDetailView(DetailView)
model = Club
# etc...
This way you only need to override specific functionality unique to each of those actions, by defining a particular method on the view class which does what you need. E.g. you need to filter the possible Clubs in the ClubListView dynamically, based on something from the request? Just override the ClubListView.get_queryset method to apply the appropriate filter.
If there is some really peculiar behaviour that needs to be applied to all the views, it depends on what this behaviour really is about: if it's related to this specific model, it should probably best be defined in the model itself, or perhaps its manager; and if it's really something specific to the views, you should write and extend a mixin along with the actual view class.
dispatch is called before post - or, for that matter, get depending on the request. Overriding it should let you set extra information.
The docs lack detail - I didn't really get it until I read the source. But the source is nicely readable except for being spread across multiple files.
You could write a get_club method in your parent class. You can then use this in your subclasses, and you don't have to repeat the logic.
I think that is the right way to ask it. I'm wondering which parts of the code execute first, second, etc.
My assumption would be, but I don't know:
Request
Middleware
View
Model
Middleware
Response
The reason I'm asking is because I want something to happen dynamicall in the Model based on a request variable and I'm trying to device the best way to automatically add the request in to the model layer without passing in via the views. I would assume that some sort of middleware fantastic contraption would be the way to do it somehow.
To answer your clarification comment -- You can't get there from here.
models.py is just a file where you put model classes, which are just classes that get accessed from all over the place. Unless the request object is passed to the function you're working with, then it does not exist, and there is no request.user. Models can be used from anywhere, not just from within contexts where there's a request.
If you need to work with the request object, then pass it as a parameter. And if that doesn't make sense, then you're using your model wrong.
Neither the model nor the templates are ever part of the stack. Do your work in a view.
I think it's more like:
Request
Middleware (URL mapper)
View
Model (if requested by the view)
Template (if requested by the view)
Middleware (response output)