Load external (absolute) URL in urlpatterns

Viewed 651

I want to associate my URL patterns in Django with an external URL because some of my views need to direct to different subdomains. Please note that all of the subdomains use the exact same Django instance, so I'm still referencing local views in my application. I just need to send a user away to a different domain in some cases. I've considered the sites framework but there are other factors preventing me from using that. The solution seems to be almost there, but I have one stumbling block.

I do this:

urlpatterns += [
    path("https://subdomain.mywebsite.com/", include("site.urls")),
]

This work. However, when I generate my URLS like so:

<a href="{% url "somepage" %}">link</a>

Then it leads to:

<a href="/https://subdomain.mywebsite.com/record/">link</a>

In other words, there is a slash in front of the URL generated. Other than that, everything works well. How can I get rid of that one?

6 Answers

as @Iain Shelvington said, do not define urlpatterns like this, they are meant to be used for paths that serve your application views

it must be,

urlpatterns += [
    path("", include("site.urls")),
        ^^^^ see, empty name
]

Then in your template,

<a href="https://subdomain.mywebsite.com{% url 'somepage' %}">link</a>

which will generate a link as,

<a href="https://subdomain.mywebsite.com/record/">link</a>

I still can't comment on posts, but the others are correct. If you want to serve a subdomain or different domain entirely, you don't want to use the URLConf. In fact, the only reason you need one is because you're trying to serve Django views, which you aren't. The other website is.

Instead, if you REALlY don't want to hard code the domain in the template, then in your Django view which is initially showing the template, you should be passing context from your Django view to your template so that the client see it as hard coded but your Django view is dynamically loading the url.

Again, those url template tags are for websites that YOUR Django is serving. If the url conf is not serving that website, then don't even bother.

You need to provide your other domain to context, so all templates could use it. create file context_processors.py

def new_domain_context_processor(request):
    return {
        'other_domain': 'YOUR_DOMAIN_URL',
    }

in setting.py

TEMPLATES = [
    {
...
        'OPTIONS': {
...
            'context_processors': [
                'django.template.context_processors.static',
                'django.template.context_processors.media',
                'django.template.context_processors.request',
...
                'YOUR_APP.context_processors.new_domain_context_processor,
            ],
...
        },
    },
]

after that you can use {{ other_domain }} in your templates

<a href="{{ other_domain }}{% url 'somepage' %}">link</a>

Let's turn this into a more concrete case. Let's say we use an account app for account management, but on a centralized subdomain "auth.example.com". We have taken all steps to ensure that session and CSRF cookies are readable on our main site "www.example.com", by setting appropriate values in settings.py. Additionally, we can turn this behavior off by setting REDIRECT_AUTH_TO_AUTH_SUBDOMAIN to False.

from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed
from django import http


class AuthRedirectMiddleware:
    AUTH_SUBDOMAIN = "auth.example.com"

    def __init__(self, get_response=None):
        if not settings.REDIRECT_AUTH_TO_AUTH_SUBDOMAIN:
            raise MiddlewareNotUsed
        self.get_reponse = get_response

    def __call__(self, request: http.HttpRequest):
        if request.get_full_path().startswith("/account/"):
            host = request.get_host()
            if host != self.AUTH_SUBDOMAIN:
                url = request.build_absolute_uri().replace(host, self.AUTH_SUBDOMAIN)
                return http.HttpResponseRedirect(url)

        return self.get_reponse()

Your urlconf would have:

urlpatterns = [
    path("account/", include("account.urls"),
    ...
]

The reverse links in templates would not have a domain name, but simply /account/login/ for example and then get redirected to the auth subdomain.

It is preferrably to use Django's the "sites" framework for that instead. To track which domain is requested. Simply by using Site.objects.get_current() in your views.

And also here django-subdomains "battery" for your goal with reverse URL with subdomains (see example below).

{% load subdomainurls %}

{% url 'home' %}
{% url 'home' 'subdomain' %}
{% url 'home' subdomain='subdomain' %}
{% url 'user-profile' username='ted' %}
{% url 'user-profile' subdomain='subdomain' username='ted' %}

Or you can add subdomain prefix using Site in template ({{ site.domain }}) or from custom RequestContext.

P.S. and definitely do NOT add subdomain to url_patterns. They are using to match everything right after domain.

Please note: as I clarified in the post I am using urlpatterns to serve application views. The exact same application is used for two different domains and I want to send people in certain cases to the other domain.

Why don't you use reverse proxy services to redirect as Nginx? And in general it would be better to direct to suburl and change domain visual in there.

Related