I have a URL pattern in Django where there is a variable (called name) that should only take one of a select list of words. Something like this:
path("profile/<marta|jose|felipe|manuela:name>/", views.profile),
So basically only these paths are valid:
profile/marta/
profile/jose/
profile/felipe/
profile/manuela/
How exactly can I configure this in the Django url patterns? The above syntax tries to illustrate the idea but doesn't work. I've seen this ten year old question but that uses the previous format in the url patterns file so I imagine it should be done differently now...?
Why not put them in view?
from django.http import Http404
def profiles(request, name):
if not name in ['marta', 'jose', 'felipe', 'manuela']:
raise Http404('You shall not pass!')
Or you can simply use re_path:
urlpatterns = [
re_path(r'^profile/(?P<name>marta|jose|felipe|manuela)/$', views.index, name='index'),
]
Related
I was reading the thread Django optional url parameters
And following the steps to generate a URL with a single optional parameter.
Well, my URL should be:
/client/
/client/?clientname=John
And I have defined two urlpatterns
url(r'^$', views.index, name='index'),
url(r'^/(?P<clientname>\d+)/',views.index),
Well, at this point both of them render the page.
But, in my view:
def index(request, clientname='noparameter'):
print("The searched name is: " + str(clientname))
The searched name is always noparameter
Am I doing something wrong?
Url you are having is
/client/John/
instead of
/client/?clientname=John
also even in the following example using John will fail as your regex is for digits , check out more on topic of django dispatcher
/client/4/
if you want to get GET parameters instead you can do that in view by using the following
request.GET.get('clientanme', None)
It seems as though you are getting confused between a keyword argument and a get request. Using keyword arguments, which your urls.py is configured for, your view would like this:
def index(request, **kwargs):
clientname = kwargs.get("clientname", "noparameter")
print("The searched name is: " + str(clientname))
Your urls.py would also have to change to this for the url to this:
url(r'^client/(?P<clientname>\w+)/',views.index),
This could be called in the browser like:
/client/John
For example is the following allowed? If so, is it not recommended or is it okay?
urlpatterns = [
url(r'^$', include('login.urls')),
url(r'^$' include('register.urls')),
url(r'^admin/', admin.site.urls),
]
Yes, you can set it up in django, but the second one will not be used, because django will find the url from top to bottom, when it found the match record, django will return the first record and stop there, so, the second one could not have chance to execute.
No, Django will math the first regex.
But you can for example set one regex for one view
and than in that view do specific operations based on the type of the request (GET/POST/PUT etc)
class CommentView(View):
def get(self, request):
... do if get type
def post(self, request):
... do if post type
And also you can check in view if user is logged in or not, if not you can redirect them to login.
I have these views in my django website. I want to redirect my users to categories like
http://sitename.com/category1/
http://sitename.com/category2/
http://sitename.com/category3/
but django detects my view names like category names if i want to go watch page or register page like:
http://sitename.com/register/
http://sitename.com/watch/
django redirects me to category view. How can i fix my problem?
url(r'^management/', include(admin.site.urls)),
url(r'^$', views.ana_sayfa),
url(r'^(.+)/', views.kategori),
url(r'^register/', views.kayit_sayfasi),
url(r'^watch/(.+)/', views.ondemand_izleme_sayfasi),
url(r'^event/(.+)/', views.live_stream_sayfasi),
url(r'^live/(.+)/', views.live_stream_izleme_sayfasi),
url(r'^buy/(.+)/', views.live_stream_satin_alma_sayfasi),
url(r'^search/(.+)/', views.arama),
url(r'^manager/', views.video_yoneticisi),
url(r'^lists/', views.listelerim),
url(r'^profile/', views.bilgilerimi_guncelle),
url(r'^messages/', views.mesajlarim),
url(r'^subscriptions/', views.abonelikler),
url(r'^settings/', views.bildirim_ayarlari),
url(r'^contact/', views.iletisim),
url(r'^help/', views.yardim),
url(r'^rss/', views.rss),
url(r'^oneall/', include('django_oneall.urls')),
Your category url pattern is evaluated before the other patterns.
You could move it to the bottom, so all of the others will be evaluated first.
So move this line to the bottom:
url(r'^(.+)/', views.kategori),
See also URL dispatching:
Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.
The URL routing patterns are evaluated in order. You need to either move your category route url(r'^(.+)/', views.kategori), down to the bottom, as ^(.+) matches everything with one or more letters plus a slash, or change the regular expression from '^(.+)/' to something like '^(category.+)/'.
Given two categories of entities, I'm selecting some kind of cross product set of them with the following URL definition:
url(r"^category1/(?P<category1>([0123456789]+,?)+)/category2(?P<category2>([0123456789]+,?)+)/$", view, {}, name="cross")
so basically URLs like /category1/1,2,3,4/category2/5,6,7,8/ are valid.
Now I introduced several views onto the same data, so that now I have URLs like /category1/1,2,3,4/category2/5,6,7,8/view1/ and /category1/1,2,3,4/category2/5,6,7,8/view2/. I would like to redirect the "old" URLs to view1. I haven't found anything easier than this:
url(r"^category1/(?P<category1>([0123456789]+,?)+)/category2(?P<category2>([0123456789]+,?)+)/$",
redirect_to, {
'url': lazy(lambda: reverse(
'cross_view1',
kwargs={
'category1': '111111',
'category2': '222222',
}
).replace('111111', '%(category1)s') \
.replace('222222', '%(category2)s'), str)(),
name="cross"}
The point here is that I want to reuse my matched groups in the URL, however, I cannot give them as kwargs to redirect_to, since they wouldn't be interpolated, and neither can I put verbatim formatting in the URL since it has to match my regex (comma-separated numeric IDs). So I introduce some unique ID (111111 and 222222 in this case) and replace them afterwards.
Obviously this feels, looks, smells and tastes very hacky. Is there any cleaner way to do this, apart from introducing an additional view and skipping redirect_to altogether?
You have some options here. You can use RedirectView, but I was unable to get it to reverse urls, since it looks like it runs before urlpatterns loads up. You can use it like so, tailor this to be used in your project:
from django.views.generic import RedirectView
Add this to your urlpatterns:
url(r'^(?P<location_id>\d+)/$', RedirectView.as_view(url='/statistics/dailyreport/%(location_id)s/')),
USE LAMBDA: This should work in most versions of django, I am using it in 1.6.5:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
....
url(r'^(?P<location_id>\d+)/$', lambda x, location_id: HttpResponseRedirect(reverse('dailyreport_location', args=[location_id])), name='location_stats_redirect'),
....
)
Just a quick note that in your reg exp you can use [0-9] instead of [0123456789]
I'm trying to use one app to satisfy multiple url paths. That is to say, I want the url /blog/ and /job/ to use the same app, but different views. There are a number of ways to do this I'm sure, but none of them seem very clean. Here's what I'm doing right now
# /urls.py
urlpatterns = patterns("",
(r"^(blog|job)/", include("myproject.myapp.urls")),
)
# /myapp/urls.py
urlpatterns = patterns("myproject.myapp.views",
(r"^(?P<id>\d+)/edit/$", "myproject.myapp.views.edit"),
(r"^(?P<id>\d+)/delete/$", "myproject.myapp.views.delete"),
(r"^(?P<id>\d+)/update/$", "myproject.myapp.views.update"),
(r"^insert/$", "myproject.myapp.views.insert"),
)
urlpatterns += patterns("",
(r"^(?P<object_id>\d+)/$", "django.views.generic.list_detail.object_detail", info_dict, "NOIDEA-detail"),
(r"^/$", "django.views.generic.list_detail.object_list", info_dict, "NOIDEA-community"),
)
# /myapp/views.py
def edit(request, type, id):
if (type == "blog"):
editBlog(request, id)
else (type == "job")
editJob(request, id)
def editBlog(request, id):
# some code
def editJob(request, id):
# some code
I've ended up breaking all of this into multiple model and view files to make the code cleaner but the above example doesn't account for things like reverse url lookups which breaks all of my template {% url %} calls.
Originally, I had blogs, jobs, events, contests, etc all living in their own apps, but all of their functionality is so similar, that it didn't make sense to leave it that way, so I attempted to combine them... and this happened. You see those "NOIDEA-detail" and "NOIDEA-community" url names on my generic views? Yeah, I don't know what to use there :-(
You can have more than one modules defining URLs. You can have /blog/ URLs in myapp/urls.py and /job/ URLs in myapp/job_urls.py. Or you can have two modules within a urls subpackage.
Alternatively you can manually prefix your url definitions:
urlpatterns = patterns("myproject.myapp.views",
(r"^jobs/(?P<id>\d+)/edit/$", "myproject.myapp.views.edit"),
(r"^jobs/(?P<id>\d+)/delete/$", "myproject.myapp.views.delete"),
(r"^jobs/(?P<id>\d+)/update/$", "myproject.myapp.views.update"),
(r"^jobs/insert/$", "myproject.myapp.views.insert"),
)
urlpatterns += patterns("",
(r"^blog/(?P<object_id>\d+)/$", "django.views.generic.list_detail.object_detail", info_dict, "NOIDEA-detail"),
(r"^blog/$", "django.views.generic.list_detail.object_list", info_dict, "NOIDEA-community"),
)
And then mount them as:
urlpatterns = patterns("",
(r"", include("myapp.urls")),
)
Personally I would go for more RESTful URL definitions though. Such as blog/(?P<post_id>\d+)/edit/$.
Looks pretty good to me. If you want reverse lookups, just have a different reverse name for each url format, even if they end up pointing to the same view.