order of matching regex in named group urls in django - regex

I'm making a blogging website with django. I'm making use of slug to identify a particular article. I'm making these blogs for 3 different fields namely sketches, cakes, and rangolis. But the problem here is, the regex of slug for urls of these three is coming to be the same. I've also named these urls for the ease but somehow can't control the order of matching the three. It is working for the named group regex of the url which is written first in the url file. I'm providing the necessary files below. My main website name is 'website' and the app name is'art'. For the order of named group urls given below the error is 'Rangoli matching query does not exist'. So only the first named group url is working. Can anyone help me resolve this. Thanks in advance!
art/urls.py
url(r'list_sketches.html$', views.sketches_list, name='sketches_list'),
url(r'list_rangolis.html$', views.rangolis_list, name='rangolis_list'),
url(r'list_cakes.html$', views.cakes_list, name='cakes_list'),
url(r'^(?P<slug>[\w-]+)/$', views.rangolis_detail, name='rangolis_detail'),
url(r'^(?P<slug>[\w-]+)/$', views.sketches_detail, name='sketches_detail'),
url(r'^(?P<slug>[\w-]+)/$', views.cakes_detail, name='cakes_detail'),
art/views.py
def sketches_list(request):
sketches = Sketch.objects.all().order_by('-date')
return render(request, 'art/list_sketches.html', {'sketches':sketches})
def sketches_detail(request, slug):
sketch = Sketch.objects.get(slug=slug)
return render(request, 'art/detail_sketches.html', {'each':sketch})
list_sketches.html
{% extends "me/base_layout.html" %}
{% block content %}
{% for each in sketches %}
<h1> {{ each.title }} </h1>
<p>{{ each.date}}</p>
<p>{{ each.snippet }}</p>
{% endfor %}
{% endblock %}
detail_sketches.html
{% extends "me/base_layout.html" %}
{% block content %}
<h1> {{ each.title }} </h1>
<p>{{ each.date}}</p>
<img src="{{ each.sketch.url}}"/>
<p>{{ each.body }}</p>
{% endblock %}

You can't use the same regex r'^(?P<slug>[\w-]+)/$' multiple times. The Django URL resolver stops as soon as it makes a match, so it will always call the rangolis_detail view.
One option is to change the regexes so that they don't clash, for example:
url(r'^rangolis/(?P<slug>[\w-]+)/$', views.rangolis_detail, name='rangolis_detail'),
url(r'^sketches/(?P<slug>[\w-]+)/$', views.sketches_detail, name='sketches_detail'),
url(r'^cakes/(?P<slug>[\w-]+)/$', views.cakes_detail, name='cakes_detail'),
Another option is to have a single detail URL pattern and view.
url(r'^(?P<slug>[\w-]+)/$', views.detail, name='detail'),
Then your detail view must fetch the correct object from the database and render the appropriate template.

Related

ValueError at /book/add Field 'id' expected a number but got 'add' --- django

A working site was bringing the collection of books with its content displayed
But when I add a function def addbook(request): it gives me a problem this:
ValueError at /book/add Field 'id' expected a number but got 'add'.
in -- all_book.html:
{% extends 'base.html' %}
{% block content %}
<h1>kljgf</h1>
Add Book
{% for book in books %}
<h3>
{{book.namebook}}
</h3>
<hr>
{% endfor %}
{% endblock content %}
in views:
def detail_book(request, id):
boo = book.objects.get(id=id)
context = {'book' : boo}
return render(request, 'detail_book.html', context)
def addbook(request):
book_form = book_form()
context = {'form' : book_form}
return render(request, 'add_book.html', context)
in url:
path('book/<id>', views.detail_book, name="detail_book"),
path('book/add', views.addbook, name="addbook"),
in add_book.html
{% extends 'base.html' %}
{% block content %}
<h1>add book </h1>
<form method="POST">
{% csrf_token %}
{{form}}
</form>
{% endblock content %}
The path book/add is ambiguous - it is being parsed as book/<id> with id = 'add'
You need to either change one of the two paths to resolve the ambiguity, or put the path for book/add before book/<id> so that the URL dispatcher matches it first.
Your urls.py will look from top to bottom for matches to your URL, so when you click /add the first match it finds is the ID query that expects a numerical ID.
Flipping the order of those two URL paths so it checks for add first, and ID only if add doesn't match should solve your problem.
This is happening because you haven't provided a type for so django is assuming 'add' is an id.
While you could fix this by changing the order to look for defined strings first, it might be more pythonic to make the difference explicit. In urls.py, add 'int' to the variable parameter as in the docs
path('book/<int:id>', views.detail_book, name="detail_book"),
path('book/add', views.addbook, name="addbook"),
Now the order doesn't matter, as integers will be assumed to be ids and non-integers can be other views.

How do I know when and when not to include the 'app_name:' in the django url tag

I was writing my first django program, following instructions from a book. The book wrote url tags like {% url 'learning_logs:index' %} (learning_logs is the app name) but when I tried to emulate that, I got an error until I went with just {% url 'index' %} after reading a post here. Later in my program, after I created another app on the same project called 'users', I was getting the error Reverse for '' not found. '' is not a valid view function or pattern name until I reverted to the initial method used in the book, adding "learning_logs:" before the page names {% url 'learning_logs:index' %}. I need some help on how to recognise when to add the 'name_of_the_app:' and when not to add it in a url tag.
Here is some code sample with the 'learning_logs:' included:
<h1>
Learning Log -
Topics -
{% if user.is_authenticated %}
Hello, {{ user.username }}
{% else %}
log in
{% endif %}
</h1>
{% block content %}{% endblock content %}
And here is how I wrote it with just the url name, which also worked sometimes (This was before I created the new app 'users':
<h1>
Learning Log -
Topics -
</h1>
{% block content %}{% endblock content %}
in the urls.py the function include(that you use to include a new urls.py for an app) has the kwarg namespace which define the namespace of the url for the app, that is what you are looking for. The main reason for this is to not collide too commons urls like "list" or "create" between apps. So if you don't define namespace you can just use the name of the url without namespace: before.
docs here: https://docs.djangoproject.com/en/3.0/topics/http/urls/#url-namespaces
hope you understand.

Reverse for 'x' not found. 'x' is not a valid view function or pattern name

I have three pages - homepage, http://127.0.0.1:8000/, displaying one paragraph sentence and two links in the header. and list of pizzas, http://127.0.0.1:8000/pizzas . Now i was trying to add links for each pizza on http://127.0.0.1:8000/pizzas page, so that one could click on them and see what toppings were available. I'm probably stuck because of my decision to use paths instead of url() for mapping urls, which the book i'm following uses.
Error : NoReverseMatch at /pizzas.
Reverse for 'pizza_w_toppings' not found. 'pizza_w_toppings' is not a valid view function or pattern name.
pizzas.html -
{% extends "pizzeria_app/base.html" %}
{% block content %}
<h1> Available Pizzas : </h1>
<ul>
{% for pizza in pizzas %}
<li> <a href = {% url 'pizza_w_toppings' %}> {{pizza}}</a><li>
{% empty %}
<p> We're outta Pizzas. next time bro! <p>
{% endfor %}
</ul>
{% endblock content %}
app/urls.py :
urlpatterns = [
#homepage
path('', views.index),
#show available pizzas
path('pizzas', views.pizzas),
path('pizzas/<int:pizza_id>', views.pizza_w_toppings, name="pizza_w_toppings")
Views:
I'm new to StackOverflow and can't figure out how to add my views.py. i attached a picture, sorry
views.py screenshot
Your url tag should be {% url 'pizza_w_toppings' pizza.id %}. If you check the documentation, you'll see all possible variations of url tag.
For example, suppose you have a view, app_views.client, whose URLconf
takes a client ID (here, client() is a method inside the views file
app_views.py). The URLconf line might look like this:
path('client/<int:id>/', app_views.client, name='app-views-client')
If this app’s URLconf is included into the project’s URLconf under a
path such as this:
path('clients/', include('project_name.app_name.urls'))
…then, in a template, you can create a link to this view like this:
{% url 'app-views-client' client.id %}
The template tag will output the string /clients/client/123/.
If you use namespaces, make sure to include namespace in your url tags like this:
{% url 'your-namespace:app-views-client' client.id %}

Using {% url 'view_name' object %} directly

The approach of doing {% url 'view_name' object.pk object.parent.slug %} isn't really flexible when switching to completety different url patterns. I'm looking for a way to do {% url 'view_name' object %} and to transcribe myself from object to object.pk and object.parent.slug in the url.
Like that
- template.html
{% url 'view_name' object %}
- urls.py [not real regex regex]
url('<object__parent__slug>/<object__pk>', views.view_name, name="view_name")
I know this is not at all possible with this syntax, but it's just to give an idea of what I'm looking for.
I will just add url methods inside my models:
class House(model.Models):
name = models.TextField()
....
def get_edit_url(self):
return reverse('view_name', {'pk':self.pk, 'name':self.name, 'owner_pk' : self.owner.pk })

Django url tag - static versus dynamic "path.to.view" parameter

I'm new to Django and puzzled. Using Django 1.4. Inside one of my templates, this code works:
{% for element0, element1 in menu.elements %}
<li class='menu_{{ name }}'>{{ element0 }}</li>
{% endfor %}
... but this code throws a "NoReverseMatch" error:
{% for element0, element1 in menu.elements %}
<li class='menu_{{ name }}'>{{ element0 }}</li>
{% endfor %}
... despite the fact that the "element1" variable holds 'users.views.home'. I'm thinking/hoping that the solution to this is really simple... that I've missed something obvious about variable handling inside Django templates?
I've consulted the documentation for the url built-in function to no avail. Any help will be appreciated.
I think you need to add this to your template:
{% load url from future %}
and change the first call to
{% url 'users.views.home' %}
see the forwards compatibility note in the docs you linked to
That's bad idea to write like this {% url 'users.views.home' %}, better use named url - {% url 'users_home' %}, it will be easy to maintain in the future. For example if you decide to move your def home(request) from users.views to account.views you will need to replace all urls occurrences in all your templates. But if you use named urls, you just need to change urls.py