Url template tag and NoReverseMatch - django

I pass array of objects from view to template, where I want to generate URLs for each object (to different view). So, I have in my URLconf:
url(r'^item/(?P<id>[0-9]+)/(?P<slug>[a-zA-Z0-9]+)$',
'show_item',
name='show_item'),
In template, I iterate on object list and try to generate URL which fits to above URL example, so I pass 2 params to each one:
{% for item in items %}
Item: {{ item.title }}, description: {{ item.description }}
URL: {% url show_item item.id item.slug %}
{% endfor %}
Unlucky, I get django error:
Reverse for 'show_item' with arguments '(1, u'first-item')' and keyword arguments '{}' not found.
What did I do wrong?

In your urls your slug regex needs to contain a hyphen (and might as well add an underscore while we're at it): (?P<slug>[a-zA-Z0-9_\-]+)

Your arguments are named:
{% for item in items %}
Item: {{ item.title }}, description: {{ item.description }}
URL: {% url show_item id=item.id slug=item.slug %}
{% endfor %}
Documentation for named groups in urls

If I'm not wrong show_item should be quoted and parameters named
{% url 'show_item' id=item.id slug=item.slug %}
also check what is generated by url using:
{% url 'show_item' id=item.id slug=item.slug as foo %}
{{ foo }}
"as foo" allows you to see the generated url without raising errors.

Related

construct url dynamically (name view as argument) with name space url tag in Django template

In a Django template, I want to construct dynamically urls
I try to concatenate (see below) but got an error :
Could not parse the remainder: '+key+'_index'' from ''ecrf:'+key+'_index''
{% for key, values in forms.items %}
<!-- for exemple a key would be 'inclusion' -->
{{ key|capfirst }}
{% endfor %}
urls
app_name='ecrf'
urlpatterns = [
path('inclusion/create/', views.InclusionCreate.as_view(), name='inclusion_create'),
expected result:
Inclusion
You can use the add template tag[Django docs] to add strings together:
{% for key, values in forms.items %}
<!-- for example a key would be 'inclusion' -->
{{ key|capfirst }}
{% endfor %}
But this feels a bit hacky to me, perhaps your forms dictionary can be restructured so that such logic is done in the view itself? For example the dictionary can be:
{'inclusion': {'value': <some_value>, 'create_url': 'ecrf:inclusion_create'}}
And in your template your loop would be:
{% for key, values in forms.items %}
<!-- for example a key would be 'inclusion' -->
{{ key|capfirst }}
{% endfor %}

How does Django get id on url?

When i clicked my menu url only gets category name and slug cant reach id how can i solve that ?
This is the url i get
def category_products (request,id,slug):
category=Category.objects.all()
products=Product.objects.filter(category_id=id)
context={'products':products,'category':category,'slug':slug, }
return render(request, 'kiliclar.html', context)
urlpatterns = [
path('category/<int:id>/<slug:slug>/', views.category_products,name='category_products'),
]
template
{% recursetree category %}
<li class="dropdown">
{{ node.title }}
{% if not node.is_leaf_node %}
<ul class="dropdown-menu">
<li>{{ children }}</li>
</ul>
{% endif %}
How does Django get id on url?
You need to supply it when you generate the "href" in the template.
The URL pattern says:
path('category/<int:id>/<slug:slug>/',
views.category_products,
name='category_products')
So the URL in the href in the template needs to look the same as the pattern:
href="/category/{{ node.id }}/{{ node.slug }}"
Or better still use the 'url' template function to expand the url from the pattern:
href="{% url category_products id=node.id slug=node.slug %}"
Here is a similar Q&A:
How to add url parameters to Django template url tag? to give you another example.
You need to add one more argument, it's id.
{{ node.title }}
It should be;
{{ node.title }}

How to overcome NoReverseMatch for link inside if statement in the template?

I want to make some value if they exist to be links.
In some case value will be None and in some case, it will have a record that user should be able to click at.
So in my template, I put it inside the if statement
{% if expense_row.noteextra.extra.id %} <a href="{% url
'extra_notes_details' pk=expense_row.noteextra.extra.id %}" class="btn
btn-info">{{ expense_row.noteextra}}</a>
{% else %}
{{ expense_row.noteextra}}
{% endif %}
But despite the if statement I still get error
NoReverseMatch at /expense/list/range/
Reverse for 'extra_notes_details' with arguments '()' and keyword arguments '{u'pk': ''}' not found. 1 pattern(s) tried: ['unit/extra_notes_details/(?P<pk>\\d+)$']
It means that Django template is being parsed for urls in early stage and it
doesn't care if those non-operational urls are inside if statement or even commented out -it will just dump an error.
How can I build those occasional links without getting the error?
Try to add method to the model:
def unit_url(self):
unit_id = getattr(self.noteunit.unit, 'id', None)
if unit_id:
return reverse('extra_notes_details', kwargs={'pk': unit_id})
and use it in template:
{% if expense_row.unit_url %}
{{ expense_row.unit_url }}
{% else %}
{{ expense_row.noteunit}}
{% endif %}
The {% url %} tag lets you assign the result to a variable. This will not raise an error if it fails to reverse the URL.
{% url 'extra_notes_details' pk=expense_row.noteextra.extra.id as the_url %}"
{% if the_url %}
{{ expense_row.noteextra}}
{% else %}
{{ expense_row.noteextra}}
{% endif %}

Combine built-in tags in templates with variables

I want to combine the built-in tag: {% url %} with a dynamic url which I parse with {{ url_value }}
I tried doing: {% url 'urlname' url_value %}, but it didn't work
This is the url:
url(r'^(?P<slug>[^/]+)/$', 'reviews.views.single_product', name='product_detail'),
{{url_value }} just represents the slug
I think it should be like:
{% url product_detail slug=url_value %}

Reference a url with an id by name in Django

I want to reference a dynamic url in my templates using its name, but am not sure how to incorporate the object id. In other words, I want to reference "/products/98" in my template without having to hard code it (as my url patterns might change).
In my urls.py, I have:
url(r'^products/(\d+)/$', 'products.views.show_product', name='product'),
How do I name my pattern such that I can call {% url ??? %} in the template to get the correct item with a specified id. e.g.
{% for product in product_list %}
Product #{% product.id %}
{% endfor %}
Use {% url product product.id %}.
urls.py:
url(r'^products/(?P<product_id>\d+)/$', 'products.views.show_product', name='product'),
template:
{% load url from future %}
{% for product in product_list %}
Product #{{ product.id }}
{% endfor %}
Make sure your products.views.show_product view function takes product_id as a parameter.