Custom Django admin site with parent url parameter - django

my url pattern looks like that:
(r'^fb/custom/(?P[a-zA-Z0-9+]*)/admin/', include(custom_admin_site.urls)),
I overrode the admin_view methode of my admin site:
def admin_view(self, view, cacheable=False):
def inner(request, *args, **kwargs):
if kwargs.has_key('custom_id'):
request.custom_id = kwargs.pop('custom_id')
return view(request, *args, **kwargs)
if not cacheable:
inner = never_cache(inner)
# We add csrf_protect here so this function can be used as a utility
# function for any view, without having to repeat 'csrf_protect'.
if not getattr(view, 'csrf_exempt', False):
inner = csrf_protect(inner)
return update_wrapper(inner, view)
This way I don't need the paramter custom_id in the view methods like index. My problem is that i can't use urlresolvers.reverse('custom-admin:index').
If I use it without parameter i get this error:
Page not found. Request URL: http://localhost:8000/fb/custom/(?P%3Ccustom_id%3E[a-zA-Z0-9%5C+]*)/admin/
Ok no suprise. I didn't provide the parameter custom_id. But with the paramter I get this error:
reverse() got an unexpected keyword argument 'custom_id'
Any idea how to solve this. I would really like to use the reverse lookup. The url template tag has the same problem.

A few issues with your url pattern:
Unless your are trying to match empty string for your custom id (which I would guess you are not) you should use + instead of *.
The + sign should go outside of your brackets.
If you are just trying to match letters and numbers, your regex can be simplified to [\w]+
Finally, if you want a named argument for custom id, you must include the name in your pattern.
So ultimately, your url patter should look like this:
(r'^fb/custom/(?P<custom_id>[\w]+)/admin/', include(custom_admin_site.urls)),
Now I'm not sure how you're trying to call urlresolvers.reverse, but if you need to pass args or kwargs, it should something look like one of these:
urlresolvers.reverse('custom-admin:index', args=[custom_id])
or for kwargs, such as in the pattern I included above:
urlresolvers.reverse('custom-admin:index', kwargs={'custom_id':custom_id})

Related

Force django querystring in url

Say you have a url like this:
/cats/?filter=kittens
Is it possible to build a django url pattern that forces the use of the querystring?
Currently I have:
url(r'^/cats/$', views.CatsListView.as_view(), name='cats')
Now I want to add the querystring and get a different view, something like this:
url(r'^/cats/?filter=(?P<filter>.+?)$', views.CatsFilteredListView.as_view(), name='cats-filtered')
Is it possible to do something like this and still keep the querystring in the GET parameter of the request?
Remember that this is just a testcase, I, and you should too, know that filtering like probably this isn't the way to go..
Short answer: no, it's not possible. Django url patterns match only on the "path" componant of the url, period.
No, it's not possible to do this. If you really need two separate views, you can write a view that dispatches the correct view.
def cat_list_view(request, *args, **kwargs):
if 'filter' in request.GET:
return cat_list_filter_view(request, *args, **kwargs)
else:
return cat_list_unfiltered_view(request, *args, **kwargs)
However, for your example of CatsListView and CatsFilteredListView there is probably a better way to combine the views. For example you might be able to do the filtering in the get_queryset method.
While it is true that you cannot manipulate the path component like that, you can pass a dictionary in. It's a 3rd unnamed argument.
This approach can be useful if you want to use the same view for multiple resources, and pass data to configure its behaviour in each case (below we supply a different template in each case).
path('url/', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'),
path('anotherurl/', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'),
Note: Both extra options and named captured patterns are passed to the view as named arguments. If you use the same name for both a captured pattern and an extra option then only the captured pattern value will be sent to the view (the value specified in the additional option will be dropped).
Courtesy of https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views

How can I pass named arguments to a Django view method?

I have a view method with two additional parameters:
def foo(request, email, token):
...
And I need to use reverse to generate a URL:
...
url = urlresolvers.reverse(
'my_app.views.foo',
kwargs={ 'token': <token>, 'email': <email> })
Is my use of reverse reasonable/acceptable, and
What does the URL pattern for foo look like?
1 - Yes, as far as it goes, but of course it will fail without the urlpattern. You can use either args or kwargs, depending on your case. Here you can use args, as they are both required args from your view function.
2 - Here's a urlpattern to get you going, but the regex is only an example, as I don't know what your regex needs to be.
url(r'^/(?P<email>[-\w]+)/(?P<token>\d{1,2})/$', 'views.foo', name='foo'),
Named urls are a good pattern to get into the habit of doing. You can pass the name to the reverse function too:
url = urlresolvers.reverse(
'foo',
args=['<email>', '<token>']
Yes
It's up to you to write it in your URLconf.
You might want to have a look at Django docs
By your question, though, it's probably better if you run through the tutorial. The third part explains how to write down the URL scheme for your site.

Django URLs: How to handle a parameter

In my url.py i have the following line:
url(r'^mypage/(?P<q_id>\d+)/$', QuizWizard.as_view(generate_form_tuples()), name='nickname'),
QuizWizard is a SessionWizardView
generate_form_tuples is a function (defined inside this module, which has an optional parameter):
def generate_form_tuples(q_id=1):
...
So, when you get on mypage/ you will (maby) have a q_id.
How can i get this parameter from the url and pass it to the generate_form_tuples() function ?
P.S. I know that if I redirect this to be handled in a view, the parameter will be sent automatically having as name : q_id
One way is to redesign it a bit, like this:
url(r'^mypage/(?P<q_id>\d+)/$', generate_form_tuples, name='nickname'),
...
def generate_form_tuples(request, q_id=1):
...
return QuizWizard.as_view(...)(request, q_id=q_id)

In Django urls. How can we make the link argument as optional .i.e. (\w+)

I want to make the arguments i pass through the urls as optional.
url(r'^dashboard/forms/(\w+)|/create/$','dashboard_message_create'),
url(r'^dashboard/forms/(\w+)/delete/$', 'delete'),
The problem with using "|" is that django cannot distinguish between the above 2 urls.
I am new to django . So any pointers in this direction will be very useful. Thanks in advance
You can try associating both with the same view
url(r'^dashboard/forms/create/$','dashboard_message_create'),
url(r'^dashboard/forms/(\w+)/create/$','dashboard_message_create'),
Then, make sure dashboard_message_create works without the argument
def dashboard_message_create(request, name=None):
# Body
You can do better, using full re-superpowers (well, almost super, no lookahead in urlpatterns...):
url(r'^dashboard/forms/((?P<name>\w+)/)?create/$','dashboard_message_create'),
url(r'^dashboard/forms/(?P<name>\w+)/delete/$', 'delete'),
Add named args to your view and ignore the unnamed ones:
def dashboard_message_create(request, name, *args, **kwargs):
pass
The name arg will be None when the ((?P<name>\w+)/)? token matches the empty string.

Capturing URL parameters in request.GET

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."