One class-based view object for multiple urls depending on parameters - python

I have multiple urls whose mission is almost identical (generate a list page with the corresponding context). So my urlpatterns is something like:
url('^by-country/(?<arg1>\w+)', MyO.as_view(), name='by-country'),
url('^by-period/(?<arg1>\w+)', MyO.as_view(), name='by-period'),
url('^by-age/(?<arg1>\w+)', MyO.as_view(), name='by-age')
Is there a way to pass the by-blabla string in a one class based view without making it as a second regex named argument in my urlpatterns?
Since I use a View derived class (i.e. MyO), I cannot pass anything to it except already-declared attributes (e.g template_name). So, is there any clean way to do it?

All url patterns accept a third positional argument, which is a dict of extra parameters to pass to the view that are not derived from the regex itself. So:
url('^by-country/(?<arg1>\w+)', MyO.as_view(), {'category': 'by-country'}, name='by-country'),

Related

Django: Passing parameters in URL as query arguments

How can I pass parameters via URL as query parameters to avoid multiple and complicated url patterns?
For example, instead of making a complicated url like
example.com/page/12/red/dog/japan/spot
or something like that, and then a corresponding entry in urls.py that will parse that url and direct it to a view, I want to simply get a url where I can freely add or remove parameters as needed similar to the ugly way
example.com/page?id=12&color=red&animal=dog&country=Japan&name=spot
Then in urls.py simply have something like
path('page/<parameter_dictionary>', views.page, name='page' parameters='parameter_dictionary)
If I have to use url patterns, how can I account for urls that have parameters that may or may not fit the pattern, such as sometimes
"/page/12/red/dog/Japan/spot" -> path('page/<int:id>/<str:color>/<str:animal>/<str:country>/<str:name>', views.page, name='page'),
"/page/12/dog/red/Japan/"-> path('page/<int:id>/<str:animal>/<str:color>/<str:country>', views.page, name='page')
"/page/dog/red/Japan/"-> path('page/<str:animal>/<str:color>/<str:country>', views.page, name='page')
I would like to just have anything sent to http://example.com/page/
go to views.page(), and then be accessible by something like
animal = request.GET['animal']
color = request.GET['color']
id = request.GET['id']
etc. so examples below would all work via one entry in urls.py
example.com/page?id=12&animal=dog&country=Japan&name=spot
example.com/page?id=12&color=red&animal=dog&name=spot
example.com/page?id=12&country=Japan&color=red&animal=dog&name=spot
You are looking for queryparameters and you are almost done with it. The following code is untested but should kinda work:
def page(request):
animal = request.GET.get("animal",None) # default None if not present
color = request.GET.get("color",None)
return render(request,'some_html.html')
# urls.py:
path('page/', views.page, name='page')
You access the queryparameters via the passed request object request.GET. This is a dict like object. The main difference is that this object handles multi keys.
For example if you pass the these params ?a=1&a=2 to your url, it converts request.GET.getlist("a") # Returns ["1","2"] to a list.
request.GET.get("a") returns the last passed value "2" as #Kbeen mentioned in comments,. Read more about QueryDict here.
Also be sure to know the difference and best practice for url parameters and queryparameters. Example Stackoverflow post
Edit: Added request.GET.getlist()

Get all parameters and their values in a request in Django [duplicate]

I am currently defining regular expressions in order to capture parameters in a URL, as described in the tutorial. How do I access parameters from the URL as part the HttpRequest object?
My HttpRequest.GET currently returns an empty QueryDict object.
I'd like to learn how to do this without a library, so I can get to know Django better.
When a URL is like domain/search/?q=haha, you would use request.GET.get('q', '').
q is the parameter you want, and '' is the default value if q isn't found.
However, if you are instead just configuring your URLconf**, then your captures from the regex are passed to the function as arguments (or named arguments).
Such as:
(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),
Then in your views.py you would have
def profile_page(request, username):
# Rest of the method
To clarify camflan's explanation, let's suppose you have
the rule url(regex=r'^user/(?P<username>\w{1,50})/$', view='views.profile_page')
an incoming request for http://domain/user/thaiyoshi/?message=Hi
The URL dispatcher rule will catch parts of the URL path (here "user/thaiyoshi/") and pass them to the view function along with the request object.
The query string (here message=Hi) is parsed and parameters are stored as a QueryDict in request.GET. No further matching or processing for HTTP GET parameters is done.
This view function would use both parts extracted from the URL path and a query parameter:
def profile_page(request, username=None):
user = User.objects.get(username=username)
message = request.GET.get('message')
As a side note, you'll find the request method (in this case "GET", and for submitted forms usually "POST") in request.method. In some cases, it's useful to check that it matches what you're expecting.
Update: When deciding whether to use the URL path or the query parameters for passing information, the following may help:
use the URL path for uniquely identifying resources, e.g. /blog/post/15/ (not /blog/posts/?id=15)
use query parameters for changing the way the resource is displayed, e.g. /blog/post/15/?show_comments=1 or /blog/posts/2008/?sort_by=date&direction=desc
to make human-friendly URLs, avoid using ID numbers and use e.g. dates, categories, and/or slugs: /blog/post/2008/09/30/django-urls/
Using GET
request.GET["id"]
Using POST
request.POST["id"]
Someone would wonder how to set path in file urls.py, such as
domain/search/?q=CA
so that we could invoke query.
The fact is that it is not necessary to set such a route in file urls.py. You need to set just the route in urls.py:
urlpatterns = [
path('domain/search/', views.CityListView.as_view()),
]
And when you input http://servername:port/domain/search/?q=CA. The query part '?q=CA' will be automatically reserved in the hash table which you can reference though
request.GET.get('q', None).
Here is an example (file views.py)
class CityListView(generics.ListAPIView):
serializer_class = CityNameSerializer
def get_queryset(self):
if self.request.method == 'GET':
queryset = City.objects.all()
state_name = self.request.GET.get('q', None)
if state_name is not None:
queryset = queryset.filter(state__name=state_name)
return queryset
In addition, when you write query string in the URL:
http://servername:port/domain/search/?q=CA
Do not wrap query string in quotes. For example,
http://servername:port/domain/search/?q="CA"
def some_view(request, *args, **kwargs):
if kwargs.get('q', None):
# Do something here ..
For situations where you only have the request object you can use request.parser_context['kwargs']['your_param']
You have two common ways to do that in case your URL looks like that:
https://domain/method/?a=x&b=y
Version 1:
If a specific key is mandatory you can use:
key_a = request.GET['a']
This will return a value of a if the key exists and an exception if not.
Version 2:
If your keys are optional:
request.GET.get('a')
You can try that without any argument and this will not crash.
So you can wrap it with try: except: and return HttpResponseBadRequest() in example.
This is a simple way to make your code less complex, without using special exceptions handling.
I would like to share a tip that may save you some time.
If you plan to use something like this in your urls.py file:
url(r'^(?P<username>\w+)/$', views.profile_page,),
Which basically means www.example.com/<username>. Be sure to place it at the end of your URL entries, because otherwise, it is prone to cause conflicts with the URL entries that follow below, i.e. accessing one of them will give you the nice error: User matching query does not exist.
I've just experienced it myself; hope it helps!
These queries are currently done in two ways. If you want to access the query parameters (GET) you can query the following:
http://myserver:port/resource/?status=1
request.query_params.get('status', None) => 1
If you want to access the parameters passed by POST, you need to access this way:
request.data.get('role', None)
Accessing the dictionary (QueryDict) with 'get()', you can set a default value. In the cases above, if 'status' or 'role' are not informed, the values ​​are None.
If you don't know the name of params and want to work with them all, you can use request.GET.keys() or dict(request.GET) functions
This is not exactly what you asked for, but this snippet is helpful for managing query_strings in templates.
If you only have access to the view object, then you can get the parameters defined in the URL path this way:
view.kwargs.get('url_param')
If you only have access to the request object, use the following:
request.resolver_match.kwargs.get('url_param')
Tested on Django 3.
views.py
from rest_framework.response import Response
def update_product(request, pk):
return Response({"pk":pk})
pk means primary_key.
urls.py
from products.views import update_product
from django.urls import path
urlpatterns = [
...,
path('update/products/<int:pk>', update_product)
]
You might as well check request.META dictionary to access many useful things like
PATH_INFO, QUERY_STRING
# for example
request.META['QUERY_STRING']
# or to avoid any exceptions provide a fallback
request.META.get('QUERY_STRING', False)
you said that it returns empty query dict
I think you need to tune your url to accept required or optional args or kwargs
Django got you all the power you need with regrex like:
url(r'^project_config/(?P<product>\w+)/$', views.foo),
more about this at django-optional-url-parameters
This is another alternate solution that can be implemented:
In the URL configuration:
urlpatterns = [path('runreport/<str:queryparams>', views.get)]
In the views:
list2 = queryparams.split("&")
url parameters may be captured by request.query_params
It seems more recommended to use request.query_params. For example,
When a URL is like domain/search/?q=haha, you would use request.query_params.get('q', None)
https://www.django-rest-framework.org/api-guide/requests/
"request.query_params is a more correctly named synonym for request.GET.
For clarity inside your code, we recommend using request.query_params instead of the Django's standard request.GET. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just GET requests."

where to define a slug without a model.py in Django

I am rather new to django, and am looking at where to define a slug in django when creating a backend without models. the url is created as such:
url(r'^main/(?P<slug>[-\w]+)/', include('main.urls')),
I have slugs within my main.urls which I define inside of each view function. Im not exactly sure where to define this slug(link, whatever you may call it). On other django slug examples, the common way is in a model, and I am currently talking to a program rather then creating my own models.
Would this be in the urls.py, or views.py (in the project, not app)?
Thank you so much. Hopefully this is understandable.
It's not hard. Really.
In url-configs each entry is simply a regular expression which has to match a url that is visited by an end user. r'^main/(?P<slug>[-\w]+)/' will for example match with: http://localhost:8000/main/some-slug/
You can use a special kind of syntax in your regular expression to extract matched data and pass that data as a variable to your view function.
The bit that does that is (?P<slug>[-\w]+) it puts matched words (in this case a slug) into a variable called slug (the <slug> part, it defines the variable name). In this humble example the slug variable will be set to "some-slug".
The variable will be accessible in your view like this:
from django.http import HttpResponse
def handle_my_view(request, slug=homepage):
# do stuff with slug
return HttpResponse("I did stuff with slug: {}".format(slug))
Learn more about, and fiddle with regular expressions
At http://www.regexr.com
But why do i see slugs used in models?:
A slug (or named variable, coming from a url 'interception') can be used for anything. Commonly the slug variable itself will be used to retrieve a database record of some sorts... And that involves using models.
You can do whatever you want with them; add stuff, subtract stuff, capitalize, whatever. The sky is the limit.
From the Django docs:
https://docs.djangoproject.com/en/1.10/topics/http/urls/#named-groups
Named groups
The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.
In Python regular expressions, the syntax for named regular-expression groups is (?Ppattern), where name is the name of the group and pattern is some pattern to match.
Here’s the above example URLconf, rewritten to use named groups:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example:
A request to /articles/2005/03/ would call the function views.month_archive(request, year='2005', month='03'), instead of views.month_archive(request, '2005', '03').
A request to /articles/2003/03/03/ would call the function views.article_detail(request, year='2003', month='03', day='03').
In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs – and you can reorder the arguments in your views’ function definitions. Of course, these benefits come at the cost of brevity; some developers find the named-group syntax ugly and too verbose.

How to redirect user to 'view' without going through smartgrid in web2py

how do i redirect a registered user to his/her db.table.id 'view' without going through smartgrid in web2py?
i have tried using:
redirect(URL(f='first', args=['mydata/view', 'mydata/%s', %request.vars.name]))
where mydata is the view for my table db.mydata and 'first' is my function.
It always returns to the smartgrid interface.
There are two problems. First, the final URL argument must be the record ID, but it looks like you are instead using a name (i.e., request.vars.name). Second, by default, the grid uses signed URLs, so you must either disable the signatures (not recommended) or add a user signature to the URL you generate. So, the link should be something like this:
redirect(URL(f='first', args=['mydata', 'view', 'mydata', request.vars.id],
user_signature=True))
Also, note that in the args list, each element can (and generally should) be a separate URL arg. So, instead of ['mydata/view', ...], it should be ['mydata', 'view', ...].

When to use slug field and query string

I am new in web development in django i don't know when to use slug field and when to use query string parameters in the url.Can anyone suggest me practical differences between them.
Using slugs keep urls simple and clean, thereby easy to remember. Consider the following example:
example.com/post/hello-world/
v/s
example.com/?post=hello-world
Obviously, first one is cleaner.
But query string parameters have their uses too. For example, when you search for an object.
example.com/search/?q=hello-world
or when you need to pass multiple parameters
example.com/search/?q=hello+world&lang=en&something=else
In slug related django urls you have a url associated to a view. But you cannot pass querystring parameters to your views.
Ex -example.com/post/hello-world/ does not pass any parameter to your view function.
But if you want to pass additional parameters to your views, ex,
example.com/search/?q=hello-world
here q=hello-world is a query string parameter passed to your views.
And inside your views function you can get these parameters in request.GET
So your views function goes something like this
def helloworld():
qParams = request.GET.get('q', '')
....
....
Hope this helps.

Categories