Loop in a URL Django - django

I wanted to access different categories through the URL, is it possible to make a loop or something like that? Which iterates until the end of the URL, no matter how much categories are there.
For example my code without this loop is below, and is limited to 6 subcategories.
urls.py
path('<cat1>/<cat2>/<cat3>/<cat4>/<cat5>/<cat6>', views.AdList.as_view(), name='ad_list'),

I guess the easiest way to go would be to add multiple urls to your urlpatterns pointing to the same view.
For instance:
# urls.py
urlpatterns = [
...
]
# if you really want urls being abled to "receive" one to 6 categories in such a way:
for i in range(1, 6):
new_url = 'cars/'
for j in range (0, i):
new_url += f"<str:cat{j}>/"
urlpatterns.append(path(r'f{new_url}', your_view.as_view(), name="your_view")
This will work, because you can have multiple urls pointing to the same view. Then, you will have to check in your view whether or not such category is provided or not.

Related

Django Regex URL pattern overriding other URLs

I am working on a project which requires to display the data about a city which is requested through the url like example.com/city1 for city1 information etc.
I have used the below url pattern & view in my app. This view is working fine.
url(r'^(?P<cityId>[-\w]+)$',views.cityindex,name='cityindex'),
def cityindex(request, cityId):
city = City.objects.filter(url = cityId)
if len(city) == 0:
return redirect('/404')
return HttpResponse('City Data Extracted')
But when I try to open other urls like /admin or urls from other app it is being redirected to my cityindex view and then to 404 page as handled in my view above.
Below is the url patterns I used in my main urls.py file.
url(r'^', include('main.urls')),
url(r'^admin/', admin.site.urls),
url(r'^login_redirect/', include('loginapp.urls')),
I am presently using Django 1.11.12. Is there any way to stop this url from overriding?
Edit :
Urls in my main.urls file
url(r'^$',views.index,name='index'),
url(r'^about$', views.aboutpage,name="aboutpage"),
url(r'^terms$', views.termspage,name="termspage"),
url(r'^privacy$', views.privacypage,name="privacypage"),
url(r'^(?P<cityId>[-\w]+)$',views.cityindex,name='cityindex'),
To achieve this, think of sceanarios like this
1- www.example.com/cityname/
2- www.example.com/about/Us/
3- www.example.com/others/terms/
4- www.example.com/others/privacy/
Anytime you want to have other url like www.example.com/faculty/list
you use number 2-4 while you use the first to achieve your city name.
I have tested this to work in the following format
urlpatterns = [
url(r'^about/us/$', views.about_page), #about us or any other page
url(r'^(?P<cityname>\w+)/$', views.cityindex), #cityname
]
and in my view.py, i can catch the city name given like this
def cityindex(request, cityname):
data = cityname
#you can do anything you want here
return HttpResponse(data)
NB: the cityname could a number so you may decide to use it as city id instead, however, ensure it was converted to an integer in your view if you prefer to use cityid
I hope this helps

How can I use a catch all route using `path` or `re_path` so that Django passes all unmatched requests to my index view?

My url patterns look like this:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
re_path('.*', IndexView.as_view()),
]
This works but it matches all URLs, including those prefixed with admin and api. I want those URLs to still match, and for any unmatched URLs to render IndexView.
Before 2.0 I used this regex for this purpose. I tried using it in re_path but that didn't work, which is what led me to trying the above.
url(r'^(?P<path>.*)/$', HtmlView.as_view())
Use case is a SPA where I handle 404s client side.
Many thanks in advance.
You can use two entries (one for '/', another one for anything else), but using path for both of them, which should be (slightly) more efficient:
urlpatterns = [
path('', IndexView.as_view(), {'resource': ''}),
path('<path:resource>', IndexView.as_view())
]
In this case, I'm using <path:resource> because path catches all resource names, inluding that with / in them. But it does not capture the main index resource, /. That's why the first entry. The dictionary as last argument for it is because we need to provide a resource parameter if we want to use the same view than in the second entry.
That view, of course, should have 'resource' as a paremeter:
def as_view(request, resource):
...
So as I said in the question description, trying the regex I was using before Django 2.0 in re_path did not work. It would basically match for all requests except / (i.e., index path). I fixed this by using both that regex and a second path matching / specifically. Here's the code:
urlpatterns = [
re_path(r'^(?P<path>.*)/$', IndexView.as_view()),
path('', IndexView.as_view()),
]
With these changes my other routes would match and these two routes would account for all other urls.
One Idea to go about this is let the django catch 404.
url.py
from django.conf.urls import handler404
handler404 = 'app_name.views.bad_request'
and in your views.py
views.py
def bad_request(request):
return redirect(reverse('home'))
You can always do some regex thingy to catch unmatched urls. but hey this gets the job done. :)

How to get a list of name arguments in Django's urlpatterns

Suppose I have two apps, App1 and App2. I want to get the list of names of each url in urlpatterns.
App1 urls.py:
urlpatterns = (
url(regex=r'^$', view=views.index_view, name='index_url'),
url(regex=r'^about/$', view=views.about_view, name='about_url'),
url(regex=r'^contact/$', view=views.contact_view, name='contact_url'),
)
In App2, I want to get the following list:
['index_url', 'about_url', 'contact_url']
I can get individual names:
>>> import App1.urls
>>> App1.urls.urlpatterns[1].name
'index_url'
Technically, I can go over a loop to collect each name in a list. But is there a direct way to get them, like: App1.urls.urlpatterns.names?
Posting the comment as an answer:
Use
names=[u.name for u in urls.urlpatterns if hasattr(u,'name')]
to populate the array of names.
It seems like there is no direct accessor.

How to go to a different page from current in Django template

urlpatterns = [
url(r'^$', predict_views.index, name = 'HomePage'),
url(r'^admin/', admin.site.urls),
url(r'^Update_db/$', predict_views.Update_db, name = 'Update_db'),
url(r'^compare/(?P<phone1_id>[0-9]+)/(?P<phone2_id>[0-9]+)/$',predict_views.Compare, name = 'Compare'),
url(r'^predict/(?P<phone_id>[0-9]+)/$',predict_views.Predict, name = 'Predict'),
]
these are my url patterns in djano. I want to go to compare directly from predict which is not possible for me currently because :
when I go to predict the url is 127.0.0.1:8000/predict/1 now when i go to compare from predict the url becomes 127.0.0.1:8000/predict/1/compare/1/2 which is not the expected url .. my url should be 127.0.0.1:8000/compare/1/2
I have seen django docs there are some redirect methods but I do not understand them.
Any help is appreciated.
Something tells me you are accidentally using relative urls. In your template, try the following:
Compare Page

Django: Passing data to view from url dispatcher without including the data in the url?

I've got my mind set on dynamically creating URLs in Django, based on names stored in database objects. All of these pages should be handled by the same view, but I would like the database object to be passed to the view as a parameter when it is called. Is that possible?
Here is the code I currently have:
places = models.Place.objects.all()
for place in places:
name = place.name.lower()
urlpatterns += patterns('',
url(r'^'+name +'/$', 'misc.views.home', name='places.'+name)
)
Is it possible to pass extra information to the view, without adding more parameters to the URL? Since the URLs are for the root directory, and I still need 404 pages to show on other values, I can't just use a string parameter. Is the solution to give up on trying to add the URLs to root, or is there another solution?
I suppose I could do a lookup on the name itself, since all URLs have to be unique anyway. Is that the only other option?
I think you can pass a dictionary to the view with additional attributes, like this:
url(r'^'+name +'/$', 'misc.views.home', {'place' : place}, name='places.'+name)
And you can change the view to expect this parameter.
That's generally a bad idea since it will query the database for every request, not only requests relevant to that model. A better idea is to come up with the general url composition and use the same view for all of them. You can then retrieve the relevant place inside the view, which will only hit the database when you reach that specific view.
For example:
urlpatterns += patterns('',
url(r'^places/(?P<name>\w+)/$', 'misc.views.home', name='places.view_place')
)
# views.py
def home(request, name):
place = models.Place.objects.get(name__iexact=name)
# Do more stuff here
I realize this is not what you truly asked for, but should provide you with much less headaches.