How to get the current url namespace using Django?
Asked Answered
C

10

109

I have to build an url dynamically according to the current url. Using the {% url %} tag is the easiest way to do it, but I need the current url namespace to generate the new one dynamically.

How can I get the url namespace attached to the urlconf that leads to the current view?

EDIT : I know I can manually handcraft the url using get_absolute_url but I'd rather avoid it since it's part of a lecture and I would like to demonstrate only one way to build urls.

The students know how to use {% url %}. They are know facing a problem when they have to generate a more complete url based on the current one. The easiest way is to use {% url %} again, with some variations. Since we have named url, we need to know how to get the name of the url that called the current view.

EDIT 2: another use case is to display parts of the base template différently according to the base template. There are other ways to do it (using CSS and {% block %}, but sometime it just nice to be able to remove the tag of the menu entry of base.html if the viewname match the link.

Chokebore answered 22/3, 2010 at 11:0 Comment(1)
I kept finding this question while searching for a way to output the current, absolute url via a template tag... if you're looking for that as well, it's: {{ request.get_full_path }}Strenta
B
157

I don't know how long this feature has been part of Django but as the following article shows, it can be achieved as follows in the view:

   from django.core.urlresolvers import resolve
   current_url = resolve(request.path_info).url_name

If you need that in every template, writing a template request can be appropriate.

Edit: APPLYING NEW DJANGO UPDATE

Following the current Django update:

Django 1.10 (link)

Importing from the django.core.urlresolvers module is deprecated in favor of its new location, django.urls

Django 2.0 (link)

The django.core.urlresolvers module is removed in favor of its new location, django.urls.

Thus, the right way to do is like this:

from django.urls import resolve
current_url = resolve(request.path_info).url_name
Binucleate answered 10/1, 2012 at 11:13 Comment(6)
Why? As far as I've understood your question, a vital part of it was how to achieve "Since we have named url, we need to know how to get the name of the url that called the current view."...Synergism
Actually lukas I was grumpy that day and discarded your answer completly arbitrarly. I apologize, because this is actually the right answer. i'm going to edit it to make it more abvious.Chokebore
resolve() cannot resolve if you pass it a query string and simply raises a 404. get_full_path() returns the path and the query string. You will need to use resolve(request.path_info).Mammalian
What if it's not current url that has to be resolved, but, say, the one a user is going to redirect to? What's a more generic way to accomplish this? Conley Owens' answer has a clue, but I'd rather not reinvent the wheel if said wheel already exists in Django under the hood.Subdued
This doesn't seem to work for translatable urls with i18n_patternsDesberg
Not wokring if the url is namespaced, use @Yeo's answer.Halation
D
141

As of Django 1.5, this can be accessed from the request object

current_url = request.resolver_match.url_name

If you would like the url name along with the namespace

current_url = request.resolver_match.view_name

https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpRequest.resolver_match

Dependency answered 12/7, 2013 at 11:37 Comment(4)
When I've put this in a context processor it worked, but this strange error was shown in the console: AttributeError: 'WSGIRequest' object has no attribute 'resolver_match'Sapper
The 'resolver_match' is added to the request object only after calling all request middleware. That is when the urls are getting resolved. So you can access only from view middleware onwards. (process_view functions of middleware). It won't be available in request middleware functions. (process_request functions of middleware).Dependency
.view_name if you need the namespaceEuroclydon
This does work well (as of Django 3.2) with i18n_patterns; i.e.: {% language language.code %}<a href="{% url request.resolver_match.view_name %}"....Ectoplasm
R
35

For those who namespace their url patterns, then you may be interested in the namespaced url name of the request. In this case, Django called it view_name instead.

request.resolver_match.view_name

# return: <namespace>:<url name>
Recidivism answered 1/7, 2016 at 19:42 Comment(2)
Thanks, but this is pretty much a dupe of @dariusz-niespodziany's earlier answer, isn't it? https://mcmap.net/q/190239/-how-to-get-the-current-url-namespace-using-djangoKeyhole
If you didn't namespace your urls.py then @dariusz-niespodziany is immediately reverse-able. But if you're using namespace, then resolver_match.url_name is not directly reverse-able. Thus you have to append the namespace yourself. So, instead of doing it yourself, Django already set the .view_name upon initialization.Recidivism
M
20

This can be achieved via:

    request.resolver_match.url_name

Django >1.8

Mantelpiece answered 11/8, 2015 at 1:35 Comment(0)
S
6

Just try request.path. That will get the current path being requested.

Sequent answered 4/4, 2020 at 7:57 Comment(1)
nice and clean (good for when you do not need domain name)Regrate
C
4

Clarification of the question: "In a view, how do you get the name of a urlpattern that points to it, assuming there is exactly one such urlpattern."

This may be desirable for the reasons stated: from within the view, we want a DRY way of getting a url to the same view (we don't want to have to know our own urlpattern name).

Short answer: It's not really simple enough to teach your class, but it might be a fun thing for you to do in an hour or two and throw up on GitHub.

If you really wanted to do this, you would have to subclass RegexURLResolver and modify the resolve method to return the matched pattern (from which you can get the pattern name) instead of the view and keyword/value pairs. http://code.djangoproject.com/browser/django/trunk/django/core/urlresolvers.py#L142

You could then create a decorator or perhaps more appropriately middleware that uses this subclass to get the pattern name and store that value somewhere in the request so that views can use it.

If you actually want to do that and you run across some trouble, let me know and I can probably help.

For your class, I would just have them hardcode the pattern name in the view or template. I believe this is the acceptable way of doing it.

Update: The more I think about this, the more I would discourage trying to get a urlpattern name in a view. urlpattern parameters are fairly independent of the parameters of the view they point to. If you want to point to a certain url, you need to know how the urlpattern works, not just how the view works. If you need to know how the urlpattern works, you might as well have to know the name of the urlpattern.

Crimp answered 4/4, 2010 at 23:10 Comment(0)
D
2

To get the absolute URL do like so:

request.build_absolute_uri()

If you want to add something extra at the end of the main ur (not current URL) do as follows:

request.build_absolute_uri("/something/")

If you want to get the only main domain URL do as below:

request.build_absolute_uri("/")
Davisdavison answered 6/11, 2022 at 18:46 Comment(1)
excellent when you need the full url along with domainRegrate
W
1

http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.get_full_path

Welsh answered 22/3, 2010 at 11:15 Comment(1)
+1 this doesn't anwser the question but does solve one problem raised in it.Chokebore
F
1

It's a little unclear from your question, but http://docs.djangoproject.com/en/dev/topics/http/urls/ will likely provide an explanation to what you're after.

Especially useful to note how Django processes requests:

When a user requests a page from your Django-powered site, this is the algorithm the system follows to determine which Python code to execute:

  1. Django determines the root URLconf module to use. Ordinarily, this is the value of the ROOT_URLCONF setting, but if the incoming HttpRequest object has an attribute called urlconf (set by middleware request processing), its value will be used in place of the ROOT_URLCONF setting.
  2. Django loads that Python module and looks for the variable urlpatterns. This should be a Python list, in the format returned by the function django.conf.urls.defaults.patterns().
  3. Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.
  4. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. The view gets passed an HttpRequest as its first argument and any values captured in the regex as remaining arguments.

If you're just after the full path, you can try:

http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.get_full_path

I hope that helps - it indicates how to use the URLconf module, and hopefully will help point you in the right direction.

Filmer answered 22/3, 2010 at 11:17 Comment(1)
Thanks but I know that :-) I added some explanations to avoid misunderstanding.Chokebore
F
0

For example, my_app1 and index are set to app_name and name respectively in my_app1/urls.py as shown below:

# "my_app1/urls.py"

from django.urls import path
from . import views

app_name = "my_app1" # Here

urlpatterns = [           # Here
    path('', views.index, name="index")
]

Then, you can get a URL namespace and it separately in my_app1/views.py as shown below:

# "my_app1/views.py"

from django.shortcuts import render

def index(request):
    print(request.resolver_match.view_name) # my_app1:index
    print(request.resolver_match.app_name) # my_app1
    print(request.resolver_match.url_name) # index
    return render(request, 'index.html')

Then, you can get a URL namespace and it separately in templates/index.html as shown below:

{# "templates/index.html" #}

{{ request.resolver_match.view_name }} {# my_app1:index #}
{{ request.resolver_match.app_name }} {# my_app1 #}
{{ request.resolver_match.url_name }} {# index #}
Forage answered 17/9, 2023 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.