Using urls names in views - django

Is it possible to use urls names in views, like we can do it in template?

Check out the docs on reverse
They have a specific example reversing a named url here:
https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
viewname is either the function name
(either a function reference, or the
string version of the name, if you
used that form in urlpatterns) or the
URL pattern name.
def myview(request):
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))

https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls
(Updated answer to point to an existing url.)

I know this topic is years old, however during my own search for the same, this one popped up. I believe the requester is looking for the following in views.py:
views.py
class Overview(ListView):
model = models.data
template_name = "overview.html"
def get_queryset(self):
name = self.request.resolver_match.url_name
print(name)
Do note that I'm using class based views. Within regular views, the name can be retrieved as follows (not tested):
def current_url_name(request):
html = "<html><body>Url name is {}.</body></html>".format(request.resolver_match.url_name)
return HttpResponse(html)
The url name is within the (self.)'request' variable. From within your view, 'resolver_match.url_name' is the one you're looking for.
Hope this helps people in search of the same.

<script>
var salesApiUrl = "{% url 'URLNamesHere' %}"
</script>
Now, the salesApiUrl is global. You can use the var name in js as well

Related

what is the differences between reverse and reverse_lazey methods in Django?

I can't use reverse() method in a class to generate url
for example, reverse() doesn't work in generic views or Feed classes (reverse_lazy() should be used instead)
but I can use reverse() in functions. what is the differences ?
take a look at following:
class LatestPostFeed(Feed):
title = 'My Django blog'
# link = reverse_lazy('blog:index')
description = 'New posts of my blog'
def items(self):
return models.Post.published.all()[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return truncatewords(item.body, 30)
def link(self):
return reverse('blog:index')
the link attribute above only works with reverse_lazy() method.
but the link function works with both reverse_lazy() and reverse() methods
reverse returns string and It's similar to the url template tag which use to convert namespaced url to real url pattern.
reverse_lazy returns object and It's a reverse() function’s lazy version. It’s prevent to occur error when URLConf is not loaded. Generally we use this function in case below:
providing a reversed URL as the url attribute of a generic class-based view.
providing a reversed URL to a decorator (such as the login_url argument for the django.contrib.auth.decorators.permission_required() decorator)
providing a reversed URL as a default value for a parameter in a function’s signature.

Providing parameters when reverse_lazy-ing a success_url redirect

TLDR: I want to be able to provide slug in reverse_lazy('view', kwargs={'slug':'my_page'}) like this: reverse_lazy('view').apply(kwargs={'slug':'my_page'}), after creating the lazy object.
I have the following url pattern that includes a slug to identify a page model instance:
url(r'^(?P<slug>'+settings.SLUG_PATTERN+')/$', views.MyView.as_view(), name='view'),
I have another view for editing the page:
url(r'^(?P<slug>'+settings.SLUG_PATTERN+')/_edit/$',
views.MyEditView.as_view(success_url=reverse_lazy('view')), name='edit'),
Note the addition of success_url so that when I submit the form with the new content I'm redirected to the now-edited page. In case I ever change my view url pattern I don't have to worry about updating the redirect for my edit url.
After the form is validated and saved, the view grabs the success url to be used in a HttpResponseRedirect. However just the name 'view' isn't enough to identify the URL. I also need to know the slug name which is stored in my page model's slug field.
A similar question is here: success_url in UpdateView, based on passed value
The answers suggest writing a custom get_success_url for every view, but there must be better approaches.
In the generic views in django's edit.py there's this:
url = self.success_url.format(**self.object.__dict__)
If success_url were given as a hard coded URL but with a slug identifier such as '{slug}/' this would replace it with the slug field in my model. That's very close to what I want, but I don't want to hard code my URL. This brings me to my question:
How can I pass in parameters to a reverse_lazy object? I would use this in my base view's get_success_url with self.object.__dict__ and it'd just work everywhere.
Moreover if my slug string was stored on separate Slug model I might want the success URL to be '{slug.name}/'. With the above approach I could supply a mapping between the URL parameters and model attributes:
redirect_model_mapping = {'slug': '{slug.name}'}
...
def get_success_url(self):
url = self.success_url
if is_a_lazy_redirect(url):
url = url.somehow_apply_parameters(redirect_model_mapping)
return url.format(**self.object.__dict__)
I would like somehow_apply_parameters to be equivalent to originally calling reverse_lazy('blog:view', kwargs=redirect_model_mapping). However I don't think this should be in urls.py because it shouldn't have to know about the mapping.
This is a hack, but does what I want...
class MyView(FormMixin, ...):
#this is actually set on child classes
redirect_model_mapping = {'slug':'{slug.name}'}
def get_success_url(self):
url = self.success_url
if url is not None:
if hasattr(self.success_url, '_proxy____kw'):
url_parameters = dict((k, v.format(**self.object.__dict__)) for k, v in six.iteritems(self.redirect_model_mapping))
url._proxy____kw = {'kwargs': url_parameters}
url = force_text(url)
else:
url = url.format(**self.object.__dict__)
else:
raise ImproperlyConfigured("No URL to redirect to.")
return url
It replaces the kwards parameter normally passed to reverse_lazy but after it actually has the values it needs. As reverse_lazy also requires the string to match the regex, I had to make the mapping between url parameters and the values in the models first.
I'd quite like an approach that doesn't need to write to _proxy____kw.

Dynamically alter urls.py to support dynamically created URLs?

I'd like to create a web service using Django that dynamically adds URLs to my urls.py file. Can this be done in Django? In other words, I'd like to have users be able to sign up for an end point that gets dynamically created using Django, e.g. my domain "dynamicurl.com" could add /johnp/ via a registration of user johnp. How would I do this?
Just create a pattern that matches the required characters for your username. Here is an example:
url(r'(?P<username>[\w.#+-]+)/$',
'yourapp.views.user_home', name='user-home'),
Then, when someone goes to yourdomain.com/johnp/ in your view you can do something like:
def user_home(request, username=None):
return render(request, 'user_home.html', {'username': username})
In user_home.html:
<strong>Welcome {{ username }}</strong>
Which will result in:
Welcome johnp
Consider this situation.
Suppose at some point in time you have a million users, your urls.py file will have a million records for user pages only. And I hope you do not wish to have separate views to handle all these separate urls.
Therefore, it is better define url patterns that can dynamically alter the content inside the templates depending on the value received within the url.
Using class based views, this can be done as follows:
In your urls.py file, write
url(r'^(?P<user_name>(.*))/$',ProfileView.as_view(),name='profile-view'),
class ProfileView(TemplateView):
template_name = "abc.html"
def get_context_data(self,**kwargs):
context = super(ProfileView,self).get_context_data(**kwargs)
context['user_name'] = kwargs['user_name']
return context
Then, in your template you can use it as {{user_name}}.

How to get_absolute_url with domain in Django template?

So I am struggling a bit, with something that logically seems so simple but due to my limited understanding of Django I am not sure where to look and how to formulate a solution.
Basically I have a Blog app set up and it shows the complete(all the content including disqus discussion) latest post on the home page. The post has a further link to the posts own page as well. I have set up Disqus and need to get some key information to use for the disqus_url and disqus_identifier. I have set up the model as follows with a method for get_absolute_url as follows:
def get_absolute_url(self):
return reverse('blog.views.renderBlog',args=[str(self.id),str(self.slug)])
My view is set up as follows:
def renderBlog(request,postid=1,slug=None):
template = 'blog_home.html'
if(postid == 1 and slug == None):
post = Post.objects.latest('date_created')
else:
post = Post.objects.get(slug=slug, id=postid)
data = {
'post':post,
}
return render(request, template, data)
As you can see the view is set up to handle both URL's as follows:
url(r'^$', 'renderBlog', name='blogHome'),
url(r'^post/(?P<postid>\d{1,4})/(?P<slug>[\w-]+)/$', 'renderBlog', name='blogPostPage'),
In my template I am setting disqus_identifier = '{{ post.get_absolute_url }}' and I am hardcoding the domain portion in the meantime as disqus_url = 'http://127.0.0.1{{ post.get_absolute_url }}';.. Same goes for the comment count <a href="" data-disqus-identifier.
I dont like doing things in a hackish manner, what would be the best method for me to get the full absolute url. I have looked at request.get_absolute_uri but am not sure on how to actually use it to get what I want.
Thanks
The way I like to do it is configure a context_processor:
from django.contrib.sites.models import Site
def base_context_processor(request):
return {
'BASE_URL': "http://%s" % Site.objects.get_current().domain
}
# or if you don't want to use 'sites' app
return {
'BASE_URL': request.build_absolute_uri("/").rstrip("/")
}
in settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
...
'path.to.base_context_processor',
...
)
(In newer versions of Django, modify context_processors under TEMPLATES, OPTIONS instead.)
then in templates:
Object Name
Another solution would be to use request.build_absolute_uri(location), but then you would have to create a template tag that takes a request object and a location or an object that has get_absolute_uri method. Then you would be able to use it templates like that: {% get_full_uri request=request obj=post %}. Here is documentation on how to write custom tags.
This question is pretty old but I think its still relevant.
To get_absolute_url with domain in Django template you can do the following:
<li>Home</li>
First check if the request is https or not and then get the request of the host and pass the absolute url.
This way you will get full URL with domain in Django template.
I know the question is old, but I'm not sure the best answer provided is the correct one.
You should just use
as the Django docs point out.
https://docs.djangoproject.com/en/4.0/ref/models/instances/#get-absolute-url
The url provided comes with the domain as well.
Regards

django-cms: urls used by apphooks don't work with reverse() or {% url %}

I'm using django-cms with apphooks to display book detail information. I need the page with the app hook to accept a slug that specifies which book to display.
I created a page called 'books' and added the apphook 'BookDetailApp'.
Here's what my books.cms_app file looks like:
class BooksApp (CMSApp):
name = _('Book Detail Page Application')
urls = ['books.urls']
apphook_pool.register(BooksApp)
Here's what my books.urls looks like:
urlpatterns = patterns('',
url(r'^(?P<slug>[\w\-]+)?', BookDetailView.as_view(), name='book_detail'),
)
And here's what my books.views file looks like:
class BookDetailView (DetailView):
model = Book
template_name = 'layouts/book-detail.html'
context_object_name = 'book'
This all works fine when I go directly to book detail page.
So going to http://localhost:8000/books/the-book-slug/ works exactly how I want to.
The problem is that I need be able to link to specific book detail pages from promos on the home page and none of the expected methods are working for me.
Using the page_url template tag from django-cms doesn't work because it only accepts one argument, so i can't provide the slug needed to determine which book to display:
go
As expected this only redirects to http://localhost:8000/books/ which throws an error because the required slug was not included.
So my next options are to use the url template tag or defining an get_absolute_url() function on the model. Neither of these options work:
go
def get_absolute_url(self):
return reverse('book_detail', args=[self.slug])
These both result in a NoReverseMatch: Reverse for 'book_detail' not found error.
If I include the books.urls conf in my main url conf then it works. So it would appear that if the url is only being used by a cms apphook that it can't be reversed by django.
Including books.urls in my main urls seems like a dirty solution and I definitely do not want to hardcode the urls in the template or the get_absolute_url function. Neither of those solutions seems very 'pythonesque'.
Any suggestions?
EDIT:
Reverse works only if I use the language namespace. According to documentation specifying language namespace shouldn't be required.
>>> reverse('en:book_detail', args=[book.slug])
This was apparently due to our application having cms.middleware.multilingual.MultilingualURLMiddleware which then forced all {% url %} template tags and the reverse() function to require the language namespace.
Since our site is not localized, removing the middleware worked fine. The documentation didn't seem that clear to me on this and finally found the answer from another source.