Django alter current URL name and arguments - django

In my Django URLs, I have many URL patterns that end with :
(redirect/(?P<redirect_to>\w+))
Which means that these URLs can be (or not) ending by /redirect/TARGET/. These URL patterns have other named arguments (mostly one : pk)
Now, I'd like, in the templates used by these URL patterns, to be able to alter the current page path, by just adding the redirect_to argument, and keeping the other arguments and URL reverse name untouched.
I was able to get the URL reverse name in the template, by adding resolve(path).url_name to the current context, and then to use that with the {% url %} template tag.
I'd like to know if there is any easy way to dynamically add the arguments (from resolve(path).kwargs) to the URL reverse tag ?

I think you should create a custom tag for this (replacing your {% url %} tag with {% url_redirect "your_new_destination" %}).
in your_app/templatetags/my_custom_tags.py:
from django.core.urlresolvers import reverse, resolve
#register.simple_tag(takes_context=True)
def url_redirect(context, new_destination):
match = resolve(context.request.path)
match.kwargs['redirect_to'] = new_destination
return reverse(match.url_name, args=match.args, kwargs=match.kwargs)
in your template:
{% load my_custom_tags %}
{% url_redirect "your_new_destination" %}
Please note that you need to add 'django.core.context_processors.request' to your TEMPLATE_CONTEXT_PROCESSORS in order for this snippet to work.

Related

Compare urls in Django Template

In a django template I don't want to show some element in case if the url/path is a specific one. In pseudo:
{% if not url = account:detail %}
We can do this in two steps here:
first we resulve the url, and assign it to a variable (here url2); and
next compare the urls
So:
{% url account:detail as url2 %}
{% if url != url2 %}
<!-- ... (do something) ... -->
{% endif %}
Note however that if two urls are syntactically different (for example yourdomain.com/foo and /foo), that they per se point to something different.
If you want access to the current path, you can - like #RajaSimon says, usually use request.path (given you render the template with a RequestContext, render(..), or another way to pass the request object).
You can give your urls a name ( url_name ) in urls.py file and then you can compare directly using HttpRequest.resolver_match object available in template.
from django.urls import path
from . import views
urlpatterns = [
path('articles/<int:year>/', views.year_archive, name='news_year_archive'),
# ...
]
In template you compare it like,
{% if request.resolver_match.url_name == "news_year_archive" %}
...your stuff
{% endif %}

Override Django Render Methods

With the following renderer...
from django.shortcuts import render
...
return render(request, 'template.html', {'context':context,})
Is it possible to override the render classe's methods so that I can in certain circumstances interpret template tags myself for example if I find a tag consisting of a certain format such as...
{% url 'website' page.slug %}
I could point it to...
/theme/theme-1/page.html
or
/theme/theme-2/page.html
depending on extranious settings.
The render method is just a shortcut for:
template = loader.get_template(''template.html')
context = {
...,
}
return HttpResponse(template.render(context, request))
Therefore, it is not the correct place to try to change the behaviour of the url tag.
For the example you have given, it looks like the website should be a variable that holds theme-1 or theme-2. You can then pass the variable to the url tag instead of the string 'website'.
{% url website page.slug %}
If that is not possible, you could create a custom template tag my_url that returns the correct url depending on your settings.

Error during template rendering

i am trying to render the details page of the product by giving the url www.example.com/product_name/product_id. But i am getting this error.
Reverse for 'product_details' with arguments '(u'lehnga choli', 43)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['(?P[a-zA-Z]*)/(?P[0-9]+)/$']
here is my urls.py
url(r'^(?P<product_name>[a-zA-Z]*)/(?P<product_id>[0-9]+)/$', 'designer.views.product_details', name='product_details'),
and here is my urls in html template
{% url 'product_details' designs.name designs.id %}
and this is my views.py
def product_details(request, product_name, product_id):
design = Design.objects.get(id=product_id)
return render_to_response("designer/product_detail.html", {
"design":design,
"current": "product_detail",
}, context_instance=RequestContext(request))
There's a space in the name (which can't be used in a URL). As I mentioned in my comment, you might want to look into a SlugField
However, since you're looking up the Design by id in your view, it doesn't really matter whether the model has a slug. You can use the template tag slugify to just make it passable through the URL.
{% url 'product_details' designs.name|slugify designs.id %}
This does require a small tweak to your URL as well, because spaces are replaced with a - - and I just use \w in general.
url(r'^(?P<product_name>[\w-]+)/(?P<product_id>[0-9]+)/$', 'designer.views.product_details', name='product_details'),

django {% url %} tag without parameters

I have a url defined as follows:
url(r'^details/(?P<id>\d+)$', DetailView.as_view(), name='detail_view'),
In my templates, I want to be able to get the following url: /details/ from the defined url.
I tried {% url detail_view %}, but I get an error since I am not specifying the id parameter.
I need the url without the ID because I will be appending it using JS.
How can I accomplish this?
Just add this line to your urls.py:
url(r'^details/$', DetailView.as_view(), name='detail_view'),
or:
url(r'^details/(?P<id>\d*)$', DetailView.as_view(), name='detail_view'),
(This is a cleaner solution - thanks to Thomas Orozco)
You'll need to specify that id is optional in your view function:
def view(request, id=None):

Can't reverse match url in Admin Changeform

I read lot's of docs, tried everything and still can't understand why my template returns Reverse for '' with arguments '(1,)' and keyword arguments '{}' not found error. Please see error dump here: http://dpaste.com/721187/
The tag I use in change_form.html template is {% url pdfview 1 %}
The class FVatAdmin(admin.ModelAdmin) has get_urls method which looks like this:
def get_urls(self):
urls = super(FVatAdmin, self).get_urls()
my_urls = patterns('',
url(r'^view/(?P<id>\d+)', self.admin_site.admin_view(self.pdf_view), name="pdfview"),
url(r'^js/calculate', self.admin_site.admin_view(self.calculate), name="calc"),
)
return my_urls + urls
The url and pdfview defined above work just fine, but somewhat don't resolve via {% url pdfview 1 %} in a template and via reverse('pdfview', args={1}) in a view or via shell.
I just can't understand what I'm doing wrong. I'm a newbie in Django... H E L P :)
Put url name in quotes.
{% url "admin:pdfview" 1 %}
UPDATE: this applies only for Django 1.3/1.4 if:
{% load url from future %}
is used.
Django admin urls are namespaced in order not to clash with other urls.
Try doing the following {% url admin:pdfview 1 %}
See this for details:
https://docs.djangoproject.com/en/1.4/topics/http/urls/#topics-http-reversing-url-namespaces