In Django's template language, you can use {% url [viewname] [args] %} to generate a URL to a specific view with parameters. How can you programatically do the same in Python code?
What I need is to create a list of menu items where each item has name, URL, and an active flag (whether it's the current page or not). This is because it will be a lot cleaner to do this in Python than the template language.
If you need to use something similar to the {% url %} template tag in your code, Django provides the django.core.urlresolvers.reverse(). The reverse function has the following signature:
reverse(viewname, urlconf=None, args=None, kwargs=None)
https://docs.djangoproject.com/en/dev/ref/urlresolvers/
At the time of this edit the import is django.urls import reverse
I'm using two different approaches in my models.py. The first is the permalink decorator:
from django.db.models import permalink
def get_absolute_url(self):
"""Construct the absolute URL for this Item."""
return ('project.app.views.view_name', [str(self.id)])
get_absolute_url = permalink(get_absolute_url)
You can also call reverse directly:
from django.core.urlresolvers import reverse
def get_absolute_url(self):
"""Construct the absolute URL for this Item."""
return reverse('project.app.views.view_name', None, [str(self.id)])
For Python3 and Django 2:
from django.urls import reverse
url = reverse('my_app:endpoint', kwargs={'arg1': arg_1})
Be aware that using reverse() requires that your urlconf module is 100% error free and can be processed - iow no ViewDoesNotExist errors or so, or you get the dreaded NoReverseMatch exception (errors in templates usually fail silently resulting in None).
Related
Suppose I have this:
from django.core.urlresolvers import reverse
url = reverse('account-list')
Assume this leads to the URL: `/account/list/'
How do I add on to the URL? I want to make that URL this: /account/list/1 (adding a pk value to the end of it). I know over here: Including a querystring in a django.core.urlresolvers reverse() call it explains how to add GET parameters (e.g. ?pk=1 but I want to know if there is a proper way for me to add on to the URL (not using GET parameters)).
I'm using DRF routers: router = routers.DefaultRouter() router.register(r'users', views.UserViewSet) and the user-detail view takes a pk value. So I want to do url = reverse('user-list') with /1 appended to the end of it.
If you are interested specifically in the detail view then you shouldn't use account-list. Assuming you have a separate account-detail view (Django Rest Framework will create these for you as well when you are using default ModelViewSets, just the same as it did with account-list):
from django.core.urlresolvers import reverse
u = reverse('account-detail', args=[1])
would be the proper way to go about this if I understand your question correctly.
You can also handle named URL parameters. For the following URL rule with a slug parameter:
url(r'/accounts/(?<slug>[a-fA-F0-9]+)/', name='account-detail', ...)
here's how you'd reverse the detail view for the account with a slug equal to something:
from django.core.urlresolvers import reverse
u = reverse('account-detail', kwargs={'slug': 'something'})
Django newbie here, need help on basic middleware to redirect to another view if a certain model field is empty.
I am creating a terms of agreement page that users must get redirected to right after they signup to the platform if their filed_terms field on their Profile model is empty.
I am using middleware for this. However I am unable to get this to work. This is my middleware class:
class TermsMiddleware(object):
def process_request(self, request):
if request.user.profile.filled_terms is None:
return redirect(reverse(terms))
This gives me the following error:
global name 'terms' is not defined
I also have the url matcher that works perfectly when I navigate to it manually:
url(r'^terms/', 'my_app.views.terms')
I have a terms.html template and a terms view in my views.py file that is working perfectly in all other respects. I have also added it to the settings middleware requirements to make sure it loads.
Do I have to import something from views or url dispatcher into my middleware file? If so what would that be? I have been at this for a while an cannot find anything helpful.
reverse function takes url name instead on the regex. So you need to add name on your url configuration. Here is the example.
url(r'^terms/', 'my_app.views.terms', name='terms')
Add this in your views.py
from django.core.urlresolvers import reverse
And you need to fix your reverse function into.
return redirect(reverse('terms'))
Python interpret your terms as a variable and you have no variable named terms while you need to put string on reverse.
I've created a django CMS apphook. Unfortunately I'm not able to reverse apphook urls using the Python shell.
The cms_app.py file looks like:
class ArticleApp (CMSApp):
name = _('Article App')
app_name = 'article_app'
urls = ['article.urls']
apphook_pool.register(ArticleApp)
This is my urls.py file:
urlpatterns = patterns('',
url(r'^(?P<slug>[\w\-]+)?', ArticleView.as_view(), name='article-by-slug'),
)
The template file is:
{% url 'article_app:article-by-slug' article.slug %}
URL reversing inside the template performs like expected. If I try to do the same using the Python shell I receive an error message:
>>> from django.core.urlresolvers import reverse
>>> from article.models import Article
>>> a = Article.objects.get(pk=1)
>>> reverse('article_app:article-by-slug', kwargs={'slug': a.slug})
# Reverse for 'article_app:article-by-slug' with arguments '()' and keyword arguments '{'slug': 'this-is-article-1'}' not found.
Additional urls defined in the main urls.py work like expected from inside the shell. Only apphook urls don't work.
Any suggestions?
Thank you!
Thanks to #Benjamin Wohlwend I was able to solve the problem. The apphook page wasn't available in the "en-us" language (the default for Django management commands like "shell"). I had to activate the correct language before reversing:
from django.utils import translation
translation.activate('de')
remove the namespace from the reverse:
reverse('article-by-slug', kwargs={'slug': a.slug})
I'm trying to do something like this:
(r'^$', RedirectView.as_view(url='^(?P<username>\w+)/$')),
but it doesn't seem to parse the regex part to the actual username...
I've done research but I can only find examples that redirect to exact urls or other regex examples that work but only in Django 1.1
Anyone have any idea how to do this in Django 1.5+?
Subclass RedirectView, and override the get_redirect_view method.
from django.core.urlresolvers import reverse
class UserRedirectView(RedirectView):
permanent = False
def get_redirect_url(self, pk):
# it would be better to use reverse here
return '/myapp/%s/' % self.request.user.username
You would include your UserRedirectView in your myapp.urls.py module as follows:
url(r'^$', UserRedirectView.as_view(), name='myapp_index'),
It would be better to reverse the url instead of hardcoding /myapp/ in the url above. As an example, if you were redirecting to a url pattern like the following
url(r'^(?P<username>\w+)/$', 'myapp.view_user', name='myapp_view_user'),
Then you could change the get_redirect_url view to:
def get_redirect_url(self, pk):
return reverse('myapp_view_user', args=(self.request.user.username,))
I think you need something like this
(r'^(?P<username>\w+)/$', 'your_view'),
where your_view is
def page(request, username):
pass
If you need redirection with parameters, you can use
('^(?P<username>\w+)/$', 'django.views.generic.simple.redirect_to',
{'url': '/bar/%(username)s/'}),
More info here:
https://docs.djangoproject.com/en/1.2/ref/generic-views/#django-views-generic-simple-redirect-to
and here:
https://docs.djangoproject.com/en/1.4/topics/http/urls/#notes-on-capturing-text-in-urls
You can try this package https://github.com/maykinmedia/django-regex-redirects. It is used in some of our projects
I have a model like this:
class EventTypeCategory(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
user = models.ForeignKey(User, verbose_name="User")
Message_slug = models.SlugField(blank=True, verbose_name="Message")
def __unicode__(self):
return self.name
In urls.py:
url(r'^categ/$',
'eventcateg_detail', name='eventcateg_detail'),
In views.py:
def eventcateg_detail(request,event_categ_id=None, event_categ_slug=None):
I want to add/edit/delete(CRUD) above defined value i.e name and Message_slug by template level. I am not getting any hint how to relate url.py with views.py and what should be definition of eventcateg_detail function.How this function will pass values to template (template name will be categ.html)
I am newbie in Django :)
want your help
You need to allow the URL to accept parameters to allow you specify which event category you want to view:
/categ/outdoor-events/
/categ/catered-events/
...
Do do this, you use a named URL pattern in your url scheme:
url(r'^categ/(?P<slug>[-\w]+)/$','eventcateg_detail', name='eventcateg_detail'),
and in your view:
from django.shortcuts import get_object_or_404, render
def eventcateg_detail(request,slug):
return render(request, "categ.html", {
'obj' : get_object_or_404(EventCateg, Message_slug =slug) # You should change Message_slug to just slug
})
and in your template:
<h1>{{ obj.name }}</h1>
So when a user enters a URL like we have outlined above, it gets matched to our URL pattern and the slug part of the url (catered-events) gets passed as a parameter to our view.
It's better that you follow the Django tutorial first, this is all covered in there. See for example part 3 of the tutorial for more information on how to relate urls.py with views.py and part 4 discusses passing variables to the template.
I believe that a view function is only passed an httprequest when it is called by the Django framework, the other two parameters of the function will only be useful if you call the function yourself but will not be useful through the web.
As pointed out in the comments I was mistaken in my belief, extra parameters can be passed as dynamic urls (i.e. urls designated like this url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),. See this link and the answer by #pastylegs
The Django Admin will allow you to edit all model fields if this is what you are after. Instructions on setting it up can be found in the Django documentation.
However I think what you are asking is how to enable CRUD editing through the web to users who are not admin level users. In that case you have many options. One of those options is to use a pre-built framework for Django like piston. Another way would be to use generic views
The other option is to build views yourself enabling operations on your model. In that case all of Django is available to you. You can pass parameters to your custom functions within the httprequest, for example as POST data.