Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
229 views
in Technique[技术] by (71.8m points)

python - Django multi tenancy

Tl; dr: Is there a way to override the default behaviour of reverse?

In my django project I have alot of urls such as

 url(r'^w+/company/', include("company.urls", namespace="company")),

Which allows for urls such as

.../companyA/company/
.../companyB/company/

So that I can then use a custom middleware to modify the request to include some specific details based upon what company is using my site

This all works fine except for when django is trying to decipher the full path with reverse and {% url .. %}...

It seems to be returning /x/company/ as a default match for the regex. since the django.utils.regex_helper method next_char has an escape mapping for w to map to x

The url tag I have been able to override to replace the /x/ with the correct company name and I am wondering if there is a similar thing I can do to override reverse in the same way, or anything else that I can do to resolve this problem?

Previously, I was using

url(r'^(?P<company_name>w+)/company/', include("company.urls", namespace="company"))

But this meant I had to include a parameter in every view

def view(request, company_name):
    ...

As well as include it in all my other calls to the view (i.e with the {% url %}) which I am trying to avoid.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For ease of use, Django packages as compiled a page full of every possible existing django package that can accomplish this. However below is my own simple implementation


I modified my nginx proxy config to use the following

server_name ~(?<short_url>w+).domainurl.com$;

... stuff related to static files here
location / {
        proxy_set_header X-CustomUrl $short_url;
        .... other proxy settings
}

What this does is create a variable inside a request header that can then be used within Django. This variable I then used within a custom middleware to extend a request with a reference to the model which allows its use anywhere.

class CompanyMiddleware(object):    
    def process_request(self, request):
        if settings.DEBUG:
            request.company = CompanyClass.objects.get(id=1)
            return None

        short_url = request.META.get("HTTP_X_CUSTOMURL")

        try:
            company = CompanyClass.objects.get(short_url=short_url)
        except Model.DoesNotExist:
            return HttpResponseBadRequest('Company not found')

        request.company = company

        return None

Examples:

www.companya.domainurl.com   # short_url is companya
test.domainurl.com           # short_url is test

To use this within a template, context processors must be added to the settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    'django.core.context_processors.request'  # This one in particular
)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...