Django optional view parameter with HttpResponseRedirect - python

So I have a view that grabs a person's info from a query and returns the info to the page:
def film_chart_view(request, if_random = False):
I also have a view that randomly grabs a person's info and redirects it to the above view:
def random_person(request):
.
.
return HttpResponseRedirect(reverse('home.views.film_chart_view')+"?q="+get_person.short)
However, I want the first view to recognize if it came from the second view, so that if it is, it sets the if_random parameter to True, but I'm not exactly sure how to do that.
my urls:
url(r'^film_chart_view/$', 'home.views.film_chart_view'),
url(r'^random/$', 'home.views.random_person'),

You don't have to pass if_random as a url parameter.
def random_person(request):
return HttpResponseRedirect(
reverse('home.views.film_chart_view') + \
"?q=" + get_person.short + \
"&is_random=1"
)
def film_chart_view(request):
is_random = 'is_random 'in request.GET
But if you prefer url parameters, the solution is a little more complex.
The parameters passed to the view function comes from the url patterns, you need to set them at first.
Because the is_random para is optional, I suggest you to write 2 separated patterns for the film_chart_view.( actually you can combine these 2 patterns to one with a more complex regex expr, but readability counts.)
urlconf:
url(r'^film_chart_view/$', 'home.views.film_chart_view', name ='film_chart_view'),
url(r'^film_chart_view/(?P<is_random>.*)/$', 'home.views.film_chart_view', name ='film_chart_view_random'),
url(r'^random/$', 'home.views.random_person'),
def random_person(request):
return HttpResponseRedirect(
reverse('home.views.film_chart_view', kwargs={'is_random': '1'}) + \
"?q=" + get_person.short
)
The view parameters(except the request) are always strings, you need to convert it to int/bool/... in you code.
def film_chart_view(request, is_random=None):
if is_random:
...

Related

Django CursorPagination for ordering by several fields

I am using Django DRF's CursorPagination for lazy loading of my data, and currently my goal is to sort the data by more than one field.
This is how my code looks like now:
class EndlessPagination(CursorPagination):
ordering_param = ''
def set_ordering_param(self, request):
self.ordering = request.query_params.get(self.ordering_param, None)
if not self.ordering:
raise ValueError('Url must contain a parameter named ' +
self.ordering_param)
if self.ordering.startswith("\"") or self.ordering.endswith("\""):
raise ValueError('Ordering parameter should not include quotation marks'
def paginate_queryset(self, queryset, request, view=None):
# This function is designed to set sorting param right in the URL
self.set_ordering_param(request)
return super(EndlessPagination, self).paginate_queryset(queryset, request, view)
This code works fine for urls like my_url/sms/270380?order_by=-timestamp, but what if I want to sort by several fields ?
Use str.split() to split the url params
class EndlessPagination(CursorPagination):
ordering_param = 'order_by'
def set_ordering_param(self, request):
ordering_param_list = request.query_params.get(self.ordering_param, None)
self.ordering = ordering_param_list.split(',')
# here, "self.ordering" will be a "list", so, you should update the validation logic
"""
if not self.ordering:
raise ValueError('Url must contain a parameter named ' +
self.ordering_param)
if self.ordering.startswith("\"") or self.ordering.endswith("\""):
raise ValueError('Ordering parameter should not include quotation marks'
"""
def paginate_queryset(self, queryset, request, view=None):
# This function is designed to set sorting param right in the URL
self.set_ordering_param(request)
return super(EndlessPagination, self).paginate_queryset(queryset, request, view)
Example URLs
1. my_url/sms/270380?order_by=-timestamp
2. my_url/sms/270380?order_by=-timestamp,name
3. my_url/sms/270380?order_by=-name,foo,-bar
UPDATE-1
First of all thanks to you for giving a chance to dig deep :)
As you said, me too didn't see comma seperated query_params in popular APIs. So, Change the url format to something like,my_url/sms/270380??order_by=-name&order_by=foo&order_by=-bar
At this time, the request.query_params['order_by'] will be a list equal to ['-name','foo','-bar']. So, you don't want to use the split() function, hence your set_ordering_param() method become,
def set_ordering_param(self, request):
self.ordering = request.query_params.get(self.ordering_param, None)
#...... your other validations

How can I show arbitrary pages based oy the URL requested in CherryPy?

For example, if the user were to go to localhost:8080/foobar228, I wouldn't need to hardcode in the request for foobar228 page by defining a function. I want to simply have a function that gives you the requested URL ("foobar228") and other information like GET and POST requests, and returns the HTML to be served. Any way to do this?
Use the default method. Here is an example.
import cherrypy
class Root:
#cherrypy.expose
def default(self, *url_parts, **params):
req = cherrypy.request
print(url_parts)
body = [
'Page served with method: %s' % req.method,
'Query string from req: %s' % req.query_string,
'Path info from req: %s' % req.path_info,
'Params (query string + body for POST): %s' % params,
'Body params (only for POST ): %s' % req.body.params
]
if url_parts: # url_parts is path_info but divided by "/" as a tuple
if url_parts[0] == 'foobar228':
body.append( 'Special foobar page')
else:
body.append('Page for %s' % '/'.join(url_parts))
else:
body.append("No path, regular page")
return '<br>\n'.join(body)
cherrypy.quickstart(Root())
The url segments becomes the positional arguments and any query string (?foo=bar) are part of the keyword arguments of the method, also the body parameters for the POST method are included in the keyword arguments (in this case under the name params in the method definition.
The special _cp_dispatch method
_cp_dispatch is a special method you declare in any of your controller to massage the remaining segments before CherryPy gets to process them. This offers you the capacity to remove, add or otherwise handle any segment you wish and, even, entirely change the remaining parts.
import cherrypy
class Band(object):
def __init__(self):
self.albums = Album()
def _cp_dispatch(self, vpath):
if len(vpath) == 1:
cherrypy.request.params['name'] = vpath.pop()
return self
if len(vpath) == 3:
cherrypy.request.params['artist'] = vpath.pop(0) # /band name/
vpath.pop(0) # /albums/
cherrypy.request.params['title'] = vpath.pop(0) # /album title/
return self.albums
return vpath
#cherrypy.expose
def index(self, name):
return 'About %s...' % name
class Album(object):
#cherrypy.expose
def index(self, artist, title):
return 'About %s by %s...' % (title, artist)
if __name__ == '__main__':
cherrypy.quickstart(Band())
Notice how the controller defines _cp_dispatch, it takes a single argument, the URL path info broken into its segments.
The method can inspect and manipulate the list of segments, removing any or adding new segments at any position. The new list of segments is then sent to the dispatcher which will use it to locate the appropriate resource.
In the above example, you should be able to go to the following URLs:
http://localhost:8080/nirvana/
http://localhost:8080/nirvana/albums/nevermind/
The /nirvana/ segment is associated to the band and the /nevermind/ segment relates to the album.
To achieve this, our _cp_dispatch method works on the idea that the default dispatcher matches URLs against page handler signatures and their position in the tree of handlers.
taken from docs

django-rest-framework : list parameters in URL

I am pretty new to django and django-rest-framework, but I am trying to pass lists into url parameters to then filter my models by them.
Lets say the client application is sending a request that looks something like this...
url: "api.com/?something=string,string2,string3&?subthings=sub,sub2,sub3&?year=2014,2015,2016/"
I want to pass in those parameters "things", "subthings", and "years" with their values.
Where the url looks something like this?
NOTE: Trick is that it won't be always an array of length 3 for each parameter.
Can someone point me in the right direction for how my url regex should be handing the lists and also retrieving the query lists in my views.
Thanks!
To show how I did this thanks to the document links above.
Note: I used pipes as my url delimiter and not commas -> '|'.
in my urls.py
url(r'^$', SomethingAPIView.as_view(), name='something'),
in my views.py
class SomethingAPIView(ListAPIView):
# whatever serializer class
def get_queryset(self):
query_params = self.request.query_params
somethings = query_params.get('something', None)
subthings = query_params.get('subthing', None)
years = query_params.get('year', None)
# create an empty list for parameters to be filters by
somethingParams = []
subthingsParams = []
yearParams = []
# create the list based on the query parameters
if somethings is not None:
for something in somethings.split('|'):
countryParams.append(int(something))
if subthings is not None:
for subthing in subthings.split('|'):
subthingsParams.append(int(subthing))
if years is not None:
for year in years.split('|'):
yearParams.append(int(year))
if somethings and subthings and years is not None:
queryset_list = Model.objects.all()
queryset_list = queryset_list.filter(something_id__in=countryParams)
queryset_list = queryset_list.filter(subthing_id__in=subthingsParams)
queryset_list = queryset_list.filter(year__in=yearParams)
return queryset_list
I do need to check for an empty result if they are not valid. But here is starting point for people looking to pass in multiple values in query parameters.
A valid url here would be /?something=1|2|3&subthing=4|5|6&year=2015|2016.
Checkout this doc http://www.django-rest-framework.org/api-guide/filtering/
Query params are normally not validated by url regex

How to obtain a single resource through its ID from a URL?

I have an URL such as: http://example.com/page/page_id
I want to know how to get the page_id part from url in the route. I am hoping I could devise some method such as:
#route('/page/page_id')
def page(page_id):
pageid = page_id
It's pretty straightforward - pass the path parameter in between angle brackets, but be sure to pass that name to your method.
#app.route('/page/<page_id>')
def page(page_id):
pageid = page_id
# You might want to return some sort of response...
You should use the following syntax:
#app.route('/page/<int:page_id>')
def page(page_id):
# Do something with page_id
pass
You can specify the ID as integer :
#app.route('/page/<int:page_id>')
def page(page_id):
# Replace with your custom code or render_template method
return f"<h1>{page_id}</h1>"
or if you are using alpha_num ID:
#app.route('/page/<username>')
def page(username):
# Replace with your custom code or render_template method
return f"<h1>Welcome back {username}!</h1>"
It's also possible to not specify any argument in the function and still access to URL parameters :
# for given URL such as domain.com/page?id=123
#app.route('/page')
def page():
page_id = request.args.get("id") # 123
# Replace with your custom code or render_template method
return f"<h1>{page_id}</h1>"
However this specific case is mostly used when you have FORM with one or multiple parameters (example: you have a query :
domain.com/page?cars_category=audi&year=2015&color=red
#app.route('/page')
def page():
category = request.args.get("cars_category") # audi
year = request.args.get("year") # 2015
color = request.args.get("color") # red
# Replace with your custom code or render_template method
pass
Good luck! :)

Django URL error

Error:
Reverse for 'charges_report' with arguments '(u'rtcl', datetime.date(2012, 1, 3), datetime.date(2012, 1, 4), u'')' and keyword arguments '{}' not found.
in my urls.py
url(r'^charges_report/(?P<company_name>[\s\w\d-]+)/(?P<start_date>[\s\w\d-]+) /(?P<close_date>[\s\w\d-]+)/(?P<batch_no>[\s\w\d-]+)/$',
'admin.reports.views.charges_report',
name='charges_report'),
and in my form views on POST
When user submits form the error is occurring. I mean on request.POST, Here is the code for form submit
if request.POST:
company_form = CompanyForm(request.POST, request=request)
if company_form.is_valid():
company_name = company_form.cleaned_data['company_name']
start_date = company_form.cleaned_data['start_date']
close_date = company_form.cleaned_data['close_date']
batch_no = company_form.cleaned_data['batch_no']
#if 'immigration_charges' in request.POST:
return HttpResponseRedirect(reverse('charges_report',args=[company_name, start_date, close_date, batch_no]))
in views
def charges_report(request, company_name, start_date, close_date, batch_no=None,):
Your URL is taking keyword arguments, but you are passing positional arguments in reverse.
Try:
kwargs = dict()
kwargs['company_name'] = company_name
kwargs['start_date'] = start_date
kwargs['close_date'] = close_date
kwargs['batch_no'] = batch_no
return HttpResponse(reverse('charges_report',kwargs=kwargs))
You also need to format your dates to match the regular expression in your URL pattern. Right now you are passing the literal string datetime.date(2012, 1, 3) as the start_date.
Change start_date (and close_date) to something that matches your regular expression, something like this:
kwargs['start_date'] = "{}".format(start_date)
kwargs['close_date'] = "{}".format(close_date)
The Django URL dispatch documentation cautions that:
"If there are any errors whilst importing any of your view functions, it will cause reverse() to raise an error, even if that view function is not the one you are trying to reverse."
"Make sure that any views you reference in your URLconf files exist and can be imported correctly."
"Do not include lines that reference views you haven't written yet." -
One of these may be your problem.
Try using a kwarg dictionary instead of positional arguments.

Categories