django {% url %} tag without parameters - django

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):

Related

django url how to use questions mark? (class based views)

in my URL for the createview, I want there to be a '?', from where I can pass an argument to the nect page. I am using class based views. For example:
www.site.com/appname/appointment/add/?Name=1
And my HTML would be:
href={% url 'People:appointment-create' Patient.id %}
Currently my URL is like so:
re_path(r'appointment/add/$', views.appointmentCreate.as_view(), name='appointment-create'),
and my view is:
class appointmentCreate(LoginRequiredMixin, CreateView):
model = appointment
form_class = AppointmentForm
def get_initial(self):
patient = self.request.GET.get('patient')
return {
'Patient': patient,
}
How would i go about doing this?
You can try something like this:
href={% url 'People:appointment-create' %}?patient_id={{ Patient.id }}
(so just pass the query arguments after the url as normally).
Also, if you want a more general solution on this problem (automatically generate the form's initial values from query parameters) take a look at this section https://spapas.github.io/#configure-the-form-s-initial-values-from-get-parameters from by article on CBVs.
So here's the basics:
first of all I would like to let you know about below line you just wrote:
{% url 'People:appointment-create' Patient.id %}
to match above url you will need to include below url:
path(r'appointment/add/<int:patient>', views.appointmentCreate.as_view(), name='appointment-create'),
This is the difference between request parameters and kwargs here you pass patient id as kwargs and access in Class base view in self.kwargs
The constructed url will be like below:
www.site.com/appname/appointment/add/1/
Next thing is that if you want to post request parameter (which don't require to add any additional url in your urls.py) you can use as below:
href="{% url 'People:appointment-create' %}?patient={{Patient.id}}"
Note that the parameter you use here will be available in view if you use name in request parameter then you need to access it as self.request.GET.get('name') and if you want to use patient as request parameter then you can access it as self.request.GET.get('patient').

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 alter current URL name and arguments

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.

Getting Django admin url for an object

Before Django 1.0 there was an easy way to get the admin url of an object, and I had written a small filter that I'd use like this: <a href="{{ object|admin_url }}" .... > ... </a>
Basically I was using the url reverse function with the view name being 'django.contrib.admin.views.main.change_stage'
reverse( 'django.contrib.admin.views.main.change_stage', args=[app_label, model_name, object_id] )
to get the url.
As you might have guessed, I'm trying to update to the latest version of Django, and this is one of the obstacles I came across, that method for getting the admin url doesn't work anymore.
How can I do this in django 1.0? (or 1.1 for that matter, as I'm trying to update to the latest version in the svn).
You can use the URL resolver directly in a template, there's no need to write your own filter. E.g.
{% url 'admin:index' %}
{% url 'admin:polls_choice_add' %}
{% url 'admin:polls_choice_change' choice.id %}
{% url 'admin:polls_choice_changelist' %}
Ref: Documentation
from django.core.urlresolvers import reverse
def url_to_edit_object(obj):
url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.model_name), args=[obj.id] )
return u'Edit %s' % (url, obj.__unicode__())
This is similar to hansen_j's solution except that it uses url namespaces, admin: being the admin's default application namespace.
I had a similar issue where I would try to call reverse('admin_index') and was constantly getting django.core.urlresolvers.NoReverseMatch errors.
Turns out I had the old format admin urls in my urls.py file.
I had this in my urlpatterns:
(r'^admin/(.*)', admin.site.root),
which gets the admin screens working but is the deprecated way of doing it. I needed to change it to this:
(r'^admin/', include(admin.site.urls) ),
Once I did that, all the goodness that was promised in the Reversing Admin URLs docs started working.
Essentially the same as Mike Ramirez's answer, but simpler and closer in stylistics to django standard get_absolute_url method:
from django.urls import reverse
def get_admin_url(self):
return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name),
args=[self.id])
Using template tag admin_urlname:
There's another way for the later versions (>=1.10), recommend by the Django documentation, using the template tag admin_urlname:
{% load admin_urls %}
Add user
Delete this user
Where opts is something like mymodelinstance._meta or MyModelClass._meta
One gotcha is you can't access underscore attributes directly in Django templates (like {{ myinstance._meta }}) so you have to pass the opts object in from the view as template context.
For pre 1.1 django it is simple (for default admin site instance):
reverse('admin_%s_%s_change' % (app_label, model_name), args=(object_id,))
I solved this by changing the expression to:
reverse( 'django-admin', args=["%s/%s/%s/" % (app_label, model_name, object_id)] )
This requires/assumes that the root url conf has a name for the "admin" url handler, mainly that name is "django-admin",
i.e. in the root url conf:
url(r'^admin/(.*)', admin.site.root, name='django-admin'),
It seems to be working, but I'm not sure of its cleanness.
If you are using 1.0, try making a custom templatetag that looks like this:
def adminpageurl(object, link=None):
if link is None:
link = object
return "%s" % (
instance._meta.app_label,
instance._meta.module_name,
instance.id,
link,
)
then just use {% adminpageurl my_object %} in your template (don't forget to load the templatetag first)
For going to the admin page or admin login page we can use the below link. It works for me -
{% url 'admin:index' %}
This url takes me directly to the admin page.
Here's another option, using models:
Create a base model (or just add the admin_link method to a particular model)
class CommonModel(models.Model):
def admin_link(self):
if self.pk:
return mark_safe(u'<a target="_blank" href="../../../%s/%s/%s/">%s</a>' % (self._meta.app_label,
self._meta.object_name.lower(), self.pk, self))
else:
return mark_safe(u'')
class Meta:
abstract = True
Inherit from that base model
class User(CommonModel):
username = models.CharField(max_length=765)
password = models.CharField(max_length=192)
Use it in a template
{{ user.admin_link }}
Or view
user.admin_link()