flask-restful how to fetch GET parameter - flask

i'm wondering how to fetch GET parameters in flask-restful like his
/hi/city?=NY
i can do like this /hi/city/NY using /hi/city/<string:ccc> but how to do so with /hi/city?=NY .
i checked the documentation and it seems like using reqparse : http://flask-restful.readthedocs.org/en/latest/reqparse.html but still couldn't figure out how

You can use the RequestParser bundled along with Flask-Restful.
from flask_restful import reqparse
class YourAPI(restful.Resource):
def get(self):
parser = reqparse.RequestParser()
parser.add_argument('city')
args = parser.parse_args()
city_value = args.get('city')
By default, the request parser searches json, form fields and query string (as it is in your case) for the key named city. The variable city_value will have the value passed in the API request.

You can use request.args.get('key')

Related

Retrieve query params with Flask-RESTful

I have a flask-RESTful endpoint defined by:
class SearchEvents(Resource):
def get(self, name, start_date, end_date):
#do stuff
api.add_resource(endpoints.SearchEvents, '/events/<string:name>/<string:start_date>/<string:end_date>')
I'm testing it manually with Postman. I'd like to pass in null values for start_date and end_date. However:
I've tried modifying the url to:
http://127.0.0.1:5000/events/test/ / #<--Spaces
and
http://127.0.0.1:5000/events/test/""/""
To no avail.
Ended up solving this by using the flask-restful request object, which has an args property which retrieves query params from the request url:
from flask_restful import request #import request from flask restful
class SearchEvents(Resource):
def get(self):
args = request.args #retrieve args from query string
api.add_resource(endpoints.SearchEvents, '/events')
And then making the requests like: http://127.0.0.1:5000/events?param1=value1&param2=value2
Or to pass null values: http://127.0.0.1:5000/events?param=&param2=value1
The values you are passing are not in the query string. You are using route parts as parameters so the route does not get matched unless you supply something of the form /events/some_name/2019-86-98/2100-9885-24515. The attempts you made are catched by flask as non matching routes and you get 404 not found.
To send those parameters as part of the query string would be to use something like
/events?name=some_name&start_date=2019-86-98&end_date=2100-9885-24515 and to get the values in your route handlers you should use name = request.args.get('name') and so on. Passing null values then means hitting the same url but without the query parameters.

Using Django Rest Framework, is it possible to get results internally on server within Django?

I have a complex DRF ViewSet that supports paging, filtering, sorting, etc. that backends a grid view. To build an "export" capability, I need to be able to take the same querystring that my endpoint uses, such as:
?obj_id=129&ordering=latitude&city__icontains=nap
And be able to, in Django, send that string into DRF somehow and get the fully-modified queryset after all the view's filters, sorts, etc are applied (the same way as the GET did). I could use the fully-rendered json response or some interim filter-applied queryset. Is it possible to use DRF in this way?
You should write a CSV renderer for your viewset and get that content-type to export the CSV.
There's even one already available.
Yes you could, if you already have a request object i.e. If you want to use this DRF viewset into another view which has the request object:
def another_view(request):
# make a copy of the `GET` attribute of request object
request.GET = request.GET.copy()
# now you can set the query params on this GET object
# ?obj_id=129&ordering=latitude&city__icontains=nap
request.GET['obj_id'] = 129
request.GET['ordering'] = 'latitude'
request.GET['city__icontains'] = 'nap'
# you can also set paging options in similar way
# now instantiate the viewset
vs = DRFViewset.as_view()
# call the view for response
# set kwargs as you need
response = vs(request, *args, **kwargs)
# response.data will have what you want here

Django: return query result as api

I'm trying to build an API server using Django. I have a few tables and I need to run queries based on the parameters passed in by url:
http://server.com/api/request/p1=123&p2=321...
and the server would extract p1 and p2 from url and run queries using them, and then return the result in json or xml.
I have tried Tastypie, and it's very easy to set up for retrieving data from one model. But my case is a bit complicated than that, and sometimes I need to run spatial queries. So if I could run the query and return result as json/xml, it would be great!
Very new to the backend technology, any help for a start point is appreciated!
Thanks!
[Edit]
Just want to make my case clearer. Say I ran a raw query using qs = cursor.execute(sql), etc., and I want to return that result as json/xml to a api call. Can I do that with either Tastypie or Rest Framework? Or can I do it without any help from 3rd party framework?
Here's a view I use return json, you should be able to adapt it pretty easy:
import json
from django.http import HttpResponse
from django.template.defaultfilters import slugify
from .models import *
def response_times(request):
response_data = {} #Create an empty dictionary
websites = Website.objects.all() #Query your models
for site in websites:
key = slugify(site.name)
response_data[key] = {}
history = History.objects.filter(website=site)[:60]
response_data[key]['response_times'] = []
for response in history:
response_data[key]['response_times'].append({'time': str(response.time), 'timestamp': response.added.strftime('%s')})
return HttpResponse(json.dumps(response_data), content_type="application/json")
It seems you have in the result QuerySet of some Model instances. So you could specify serializer to work with your model and use it to serialize from model instances to native python data using Rest Framework. Look here for details.

Django REST framework: non-model serializer

I am beginner in Django REST framework and need your advice. I am developing a web service. The service has to provide REST interface to other services. The REST interface, which I need to implement, is not working with my models directly (I mean the get, put, post, delete operations). Instead, it provides other services with some calculation results. On a request my service makes some calculations and just returns the results back (doesn't store the results in its own database).
Below is my understanding of how that REST interface could be implemented. Correct me, if I am wrong.
Create class which makes the calculations. Name it 'CalcClass'. CalcClass uses the models in its work.
Params necessary for the calculations are passed to the constructor.
Implement the calc operation. It returns results as 'ResultClass'.
Create ResultClass.
Derived from object.
It just only has attributes containing the calc results.
One part of the calc results is represented as tuple of tuples. As I understand, it would be better for further serialization to implement a separate class for those results and add list of such objects to ResultClass.
Create Serializer for ResultClass.
Derive from serializers.Serializer.
The calc results are read-only, so use mostly Field class for fields, instead of specialized classes, such as IntegerField.
I should not impl save() method neither on ResultClass, nor on Serializer, because I am not going to store the results (I just want to return them on request).
Impl serializer for nested results (remember tuple of tuples mentioned above).
Create View to return calculation results.
Derive from APIView.
Need just get().
In get() create CalcClass with params retrieved from the request, call its calc(), get ResultClass, create Serializer and pass the ResultClass to it, return Response(serializer.data).
URLs
There is no api root in my case. I should just have URLs to get various calc results (calc with diff params).
Add calling format_suffix_patterns for api browsing.
Did I miss something? Is the approach is correct in general?
Django-rest-framework works well even without tying it to a model. Your approach sounds ok, but I believe you can trim some of the steps to get everything working.
For example, rest framework comes with a few built-in renderers. Out of the box it can return JSON and XML to the API consumer. You can also enable YAML by just installing the required python module. Django-rest-framework will output any basic object like dict, list and tuple without any extra work on your part.
So basically you only have to create the function or class that takes in arguments, does all of the required calculations and returns its results in a tuple to the REST api view. If JSON and/or XML fits your needs, django-rest-framework will take care of the serialization for you.
You can skip steps 2 and 3 in this case, and just use one class for calculations and one for presentation to the API consumer.
Here are a few snippets may help you out:
Please note that I have not tested this. It's only meant as an example, but it should work :)
The CalcClass:
class CalcClass(object):
def __init__(self, *args, **kw):
# Initialize any variables you need from the input you get
pass
def do_work(self):
# Do some calculations here
# returns a tuple ((1,2,3, ), (4,5,6,))
result = ((1,2,3, ), (4,5,6,)) # final result
return result
The REST view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from MyProject.MyApp import CalcClass
class MyRESTView(APIView):
def get(self, request, *args, **kw):
# Process any get params that you may need
# If you don't need to process get params,
# you can skip this part
get_arg1 = request.GET.get('arg1', None)
get_arg2 = request.GET.get('arg2', None)
# Any URL parameters get passed in **kw
myClass = CalcClass(get_arg1, get_arg2, *args, **kw)
result = myClass.do_work()
response = Response(result, status=status.HTTP_200_OK)
return response
Your urls.py:
from MyProject.MyApp.views import MyRESTView
from django.conf.urls.defaults import *
urlpatterns = patterns('',
# this URL passes resource_id in **kw to MyRESTView
url(r'^api/v1.0/resource/(?P<resource_id>\d+)[/]?$', login_required(MyRESTView.as_view()), name='my_rest_view'),
url(r'^api/v1.0/resource[/]?$', login_required(MyRESTView.as_view()), name='my_rest_view'),
)
This code should output a list of lists when you access http://example.com/api/v1.0/resource/?format=json. If using a suffix, you can substitute ?format=json with .json. You may also specify the encoding you wish to get back by adding "Content-type" or "Accept" to the headers.
[
[
1,
2,
3
],
[
4,
5,
6
]
]

Can i access the response context of a view tested without the test client?

I have a function which i call from a unittest. From setting some debug traces i know the function worked like a charm and has all the values correctly prepared for return.
This is what my testcode looks like (see where my ipdb.set_trace() is ):
#override_settings(REGISTRATION_OPEN=True)
def test_confirm_account(self):
""" view that let's a user confirm account creation and username
when loggin in with social_auth """
request = self.factory.get('')
request.user = AnonymousUser()
request.session={}
request.session.update({self.pipename:{'backend':'facebook',
'kwargs':{'username':'Chuck Norris','response':{'id':1}}}})
# this is the function of which i need the context:
response = confirm_account(request)
self.assertEqual(response.context['keytotest'],'valuetotest')
From what i know from this part of the Django docs, i would be able to access response.context when i have used the testing client. But when i try to access response.context like i did it, i get this:
AttributeError: 'HttpResponse' object has no attribute 'context'
Is there a way to get the special HttpResponse object of the client, without using the client?
The RequestFactory does not touch the Django middleware, and as such, you will not generate a context (i.e. no ContextManager middleware).
If you want to test the context, you should use the test client. You can still manipulate the construction of the request in the test client either using mock or simply saving your session ahead of time in the test, such as:
from django.test import Client
c = Client()
session = c.session
session['backend'] = 'facebook'
session['kwargs'] = {'username':'Chuck Norris','response':{'id':1}}
session.save()
Now when you load the view with the test client, you'll be using the session as you set it, and when you use response = c.get('/yourURL/'), you can then reference the response context using response.context as desired.
The "response.context" is incorrect for new django versions but you can use response.context_data to get the same context that passed to TemplateResponse.
Though this is an old post, I suppose this tip can be of help. You can look into using TemplateResponse (or SimpleTemplateResponse) which can be substituted for render or render_to_response.
The Django docs has more on this
Yes, you can. You have to patch render.
I'm using pytest-django
class Test:
def context(self, call_args):
args, kwargs = call_args
request_mock, template, context = args
return context
#patch('myapplication.views.render')
def test_(self, mock_render, rf):
request = rf.get('fake-url')
view(request)
context = self.context(mock_render.call_args)
keytotest = 'crch'
assert keytotest == context['keytotest']
context (sic!) can be found in Response class. As you see it says it's HTTPResponse you get back from the view function. This happened because you've called it directly. Call this function via test client and it will be okay.
response = client.get('/fobarbaz/')
response.context