django rest framework request vs self.request - django

in djnago rest framework what is difference between self.request and request in
why we cant always use request and exactly in what situations we need to use self.request or request
class MyView(APIView):
def post(self, request, format=None):
data = self.request.data
login(request, user)
i try to print them and both of them return same thing
<rest_framework.request.Request: POST '/url/sub_url'>
so why we user like
data = self.request.data
login(request, user)

the request argument is passed to the post method. like any normal function that you can define and use its arguments.
But since post is a method it takes self argument. you can access the class methods and attributes including request.
And they're the same.
When request is passed to your function just use request but if not and you need request use self.request.

If you are using function based views, you wont be able to use self.request. Here as you are using class based views, you can access it both ways.

Related

How to get a testing http request in django testcase?

I'm working in a solution with only an GraphQL API, so all my logic are in forms. The save method of one of my forms receives the http request. I use the request to get some data for mailing. So, I'm trying to make a test case of this form but I don't know how to pass the request object.
class SignUpForm(forms.ModelForm):
...
def save(self, request, *args, **kwargs):
...
How can I pass the request object to form in a test case?
You can instantiate HttpRequest and use it as a regular request in your test:
fake_request = HttpRequest()
fake_request.user = AnonymousUser()
fake_request.META['SERVER_NAME'] = site.domain
fake_request.META['SERVER_PORT'] = 80
s = SessionStore()
s.create()
fake_request.session = s
In your case you might need to fill more fields

How to do dynamic dispatch in Django REST Framework without an extra request?

I've got a bunch of existing API endpoints with different URLs and parameters. I'd like to enable asynchronous execution of some of them by adding a general-purpose /tasks(?P<path>.+) endpoint which calls the path endpoint asynchronously, returning a Celery task ID for the client to check the status of the task at their leisure. So far it's very similar to another question, but I was hoping there would be an existing pattern to resolve and call the relevant view without sending another HTTP request. Even though it would be fast enough to send a request, it would be seemingly unnecessary complexity.
It seems this might be possible at the view level, basically stripping off the URL prefix and then using the built-in URL resolver to figure out what to call asynchronously with a slightly modified request object.
This is just an example, the implementation depends on how your code is organized.
Assume you have the following ViewSet, mapped to the url '/example':
class ExampleViewSet(ViewSet):
def list(self, request, *args, **kwargs):
result = some_task()
return Response(result)
Now you can create a second ViewSet and map it to example/async, or tasks/example:
class ExampleAsyncViewSet(ViewSet):
def list(self, request, *args, **kwargs):
result = some_task.delay()
return Response({"task_id": result.id})
You could also use an argument or a query param:
class ExampleViewSet(ViewSet):
def list(self, request, *args, **kwargs):
if (kwargs.get("async") is True: # or request.query_params.get("async") ...
result = some_task.delay()
return Response({"task_id": result.id})
result = some_task()
return Response(result)

Django REST Framework Deep Dive - Where is it determined that an enpoint needs an auth token

general django question for those who are more experienced than myself,
I'm reading through the code posted for a tutorial on thinkster.io:
https://github.com/howardderekl/conduit-django/tree/master/conduit/apps
There's an endpoint pertaining to the User model authenticion/models.py that requires an Authorization header for it to return user information defined here in authentication/views.py:
class UserRetrieveUpdateAPIView(RetrieveUpdateAPIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserJSONRenderer,)
serializer_class = UserSerializer
def retrieve(self, request, *args, **kwargs):
serializer = self.serializer_class(request.user)
return Response(serializer.data, status=status.HTTP_200_OK)
My question is how/where is it (supposed to be) determined that an endpoint requires this Authorization. My thought is that it is tied to the permission_classes variable stated in the UserRetrieveUpdateAPIVIiew class above. I dug into the package location where this was imported from (from rest_framework.permissions import IsAuthenticated), but that doesn't appear to contain anything pertaining to an HTTP header:
class BasePermissionMetaclass(OperationHolderMixin, type):
pass
class BasePermission(metaclass=BasePermissionMetaclass):
"""
A base class from which all permission classes should inherit.
"""
def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
...
...
...
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
I'm looking for best practices on how to structure headers like this for HTTP methods in my backend. Any ideas on where I should look, somewhere in settings.py maybe?
Thanks!
Bonus question:
This header requires two strings in your request. First being 'Token', followed by a space, then the actual JWT for that user. Is this standard practice to use two strings like this? If so, what's the reasoning. I've seen this before with other seemingly arbitrary words used for the first string, 'Token'
As shown in the documentation :
REST framework will attempt to authenticate with each class in the list, and will set request.user and request.auth using the return value of the first class that successfully authenticates.
So if you use a token authentication scheme, the header Authorization: Token ... will result in the setup of the request.user and request.user.is_autenticated will be set to true for the view.
By combining it with the IsAuthenticated permission class, the view will only be accessible if the authorization token is set (and if you don't allow other authentication schemes)
For your second question, you can indeed put any string you want. Here DRF uses Token to make it clearer for which authentication scheme it is used. Since a lot of apps also uses a "Token", a lot of them use the same word. You can also often find Bearer.
Django REST Framework comes with a package for Token Authentication, which is probably what you are looking for:
https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
With it, you can assign tokens to individual users, which they can use in lieu of a username and password to authenticate against endpoints. This token is provided in the HTTP header. As for your second question, by providing Token as a convention, it would allow for other custom authentication types:
https://www.django-rest-framework.org/api-guide/authentication/#custom-authentication
The permission_classes are what determine what, if any, authentication is necessary. Good luck!

Check in DeleteView if its post or get? django

Im trying to check either a user tried to enter a url by himself or he follows the urls and put the values needed in the form i build for him..
In some Ungeneric class, I can check that thing -
if request.method == 'GET':
But in DeleteView i can't do that thing so i don't know how to prevent from the user from doing bad things by input url by himself.
How can i use a function that does the same in generic View and checks if the user enter a url by himself or fill in the form?
It should be a POST, there isn't any need to check it yourself.
From the docs
The given object will only be deleted if the request method is POST. If this view is fetched via GET, it will display a confirmation page that should contain a form that POSTs to the same URL.
By default DeleteView does deletion only on POST request. So your user will not be able to delete items just making GET request.
But for your information all class based views(CBV) call dispatch method which then calls ether post or get depending on request.method.
You can add some logic directly in dispatch method or modify get and do your checks there
Example
class MyDeleteView(DeleteView):
def post(self, request, *args, **kwargs):
...
def get(self, request, *args, **kwargs):
# here you can make redirect to any url
...

MemoryError in django-rest-framework CreateAPIView due to unnecessary queries

I want to create an object using the CreateAPIView from the django-rest-framework. When calling the view, I get a MemoryError. That's probably because the view tries to present all 350000 existing objects in the browseable response.
How should I prevent the view from performing the corresponding query? Defining a post or a get_queryset method does not help.
I solved the problem by using the APIView instead of the CreateAPIView. Here's the class I wrote:
class VoteCreateAPIView(views.APIView):
def post(self, request, *args, **kwargs):
vote = request.POST.get('vote', '')
# here some validation
Vote.objects.create(
user=request.user,
vote=vote)
return response.Response({'vote': vote}, status=status.HTTP_200_OK)
I would still be curious if there's a better way to do it.