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
Related
I am trying to test a Django Rest Framework view. When I call my endpoint from a real api client, pk is correctly set. When it is called from the test, pk is None.
class ResourceViewSet(ModelViewSet):
serializer_class = ResourceSerializer
#action(detail=True)
def foo(self, request, pk=None):
print(pk) # None when called by the test
def test_foo(client: Client, db):
request = factory.post(f'/api/resource/1/foo/')
view = ResourceViewSet.as_view({'post': 'foo'})
response = view(request)
How should I fix my test?
When testing the view directly as you are doing, you are bypassing the url resolving/mapping logic. Therefore, you should pass the parameters as args/kwargs, in the end you are calling the foo function:
def test_foo(client: Client, db):
request = factory.post(f'/api/resource/1/foo/')
view = ResourceViewSet.as_view({'post': 'foo'})
response = view(request, pk=1)
If you'd like to test the whole stack, also the urls, I'd recommend you use the APIClient.
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.
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)
I am using django 1.11.9
I want to add client_id and client_secret to the django POST request.
Here is how my middleware.py file looks like:
class LoginMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# auth_header = get_authorization_header(request)
# Code to be executed for each request before
# the view (and later middleware) are called.
#Add Django authentication app client data to the request
request.POST = request.POST.copy()
request.POST['client_id'] = '12345678'
request.POST['client_secret'] = '12345678'
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
Middleware is being successfully processed when I check it with a debugger. Thought when a view is called the 'client_id' and 'client_secret' fields are missing in the request.
After some experimenting i figure out that request is not getting updated and when it is called in a different view, it returns old values.
I am later using request in rest_framework_social_oauth2. And this is the point when 'client_id' and 'client_secret' disappear.
class ConvertTokenView(CsrfExemptMixin, OAuthLibMixin, APIView):
"""
Implements an endpoint to convert a provider token to an access token
The endpoint is used in the following flows:
* Authorization code
* Client credentials
"""
server_class = SocialTokenServer
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
oauthlib_backend_class = KeepRequestCore
permission_classes = (permissions.AllowAny,)
def post(self, request, *args, **kwargs):
import pdb ; pdb.set_trace()
# Use the rest framework `.data` to fake the post body of the django request.
request._request.POST = request._request.POST.copy()
for key, value in request.data.items():
request._request.POST[key] = value
url, headers, body, status = self.create_token_response(request._request)
response = Response(data=json.loads(body), status=status)
for k, v in headers.items():
response[k] = v
return response
I need to add client_id and client_secret to the request body, so it can be later used by rest_framework_social_oauth2.
What could be the problem? How to properly update the request?
As you're working with request and processing a request, you have to implement process_request method, so the result will be something like:
class LoginMiddleware(object):
def process_request(self, request):
request.session['client_id'] = '12345678'
and then in your view:
def your_view(request):
client_id = request.session['client_id']
I'd like to send an email once a POST has been successfully completed. It seems to make sense that the email would be done with a signal. I can write my own, as documented here: https://docs.djangoproject.com/en/1.6/topics/signals/#defining-and-sending-signals
However, what I can't figure out is:
Does Django Rest Framework support signals (why wouldn't it, it's just Django)
What do I listen to to send the custom signal? What is the sender?
Suggestions welcome.
Also, is anyone doing this with Angular? Is there a simple way to do this that I'm not seeing?
Old question for an old version of Django, but if anyone comes across it... It's not necessary to use signals. Django now has the built-in function send_mail. Here's the documentation:
https://docs.djangoproject.com/en/1.8/topics/email/
So you would use that function to create and send an email. It can even accept an HTML template as the message argument and populate it w/ Django data, which is nice.
So you'd define a function that included this method, for example:
def email_client(request):
id = request.POST.get('id')
client = Client.objects.get(id=id)
msg_html = render_to_string('templates/email.html', {'client': client})
template_email_text = ''
return send_mail('Lelander work samples', template_email_text, 'test#emailsender.com', ['test#emailrecipient.com'], html_message=msg_html, fail_silently=False)
And include that function in your DRF API view in post:
class ClientList(generics.ListCreateAPIView):
queryset = Client.objects.all()
serializer_class = ClientSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
email_client(request)
return self.create(request, *args, **kwargs)
Yes, DRF supports signals.
I don't have a good answer for question 2, mainly because I think the best place to do this is in the post_save method of your class. That way, you are sure your object was created, you have access to the object and to the request and you don't need to bother implementing signals (which would probably require another class just for email sending).