How to make Django url dispatcher use subdomain? - django

I have a vague idea on how to solve this, but really need a push :)
I have a Django app running with apache (mod_wsgi). Today urls look like this:
http://site.com/category/A/product/B/
What I would like to do is this:
http://A.site.com/product/B
This means that the url dispatcher some how needs to pick up the value found in the subdomain and understand the context of this instead of only looking at the path. I see two approaches:
Use .htaccess and rewrites so that a.site.com is a rewrite. Not sure if this does the trick since I don't fully understand what the django url dispatcher framework will see in that case?
Understanding how the url dispatcher DO work I could write a filter that looks at valid sub domains and provides this in a rewritten format to the url dispatcher code.
Any hints or solutions are very much appreciated! Thanks.

Have you looked at django.contrib.sites? I think a combination of that, setting SITE_ID in your settings.py, and having one WSGI file per "site" can take care of things.
EDIT: -v set.
django.contrib.sites is meant to let you run multiple sites from the same Django project and database. It adds a table (django.contrib.sites.models.Site) that has domain and name fields. From what I can tell, the name can mean whatever you want it to, but it's usually the English name for the site. The domain is what should show up in the host part of the URL.
SITE_ID is set in settings.py to the id of the site being served. In the initial settings.py file, it is set to 1 (with no comments). You can replace this with whatever code you need to set it to the right value.
The obvious thing to do would be to check an environment variable, and look up that in the name or domain field in the Site table, but I'm not sure that will work from within the settings.py file, since that file sets up the database connection parameters (circular dependency?). So you'll probably have to settle for something like:
SITE_ID = int(os.environ.get('SITE_ID', 1)
Then in your WSGI file, you do something like:
os.environ['SITE_ID'] = 2
and set that last number to the appropriate value. You'll need one WSGI file per site, or maybe there's a way to set SITE_ID from within the Apache setup. Which path to choose depends on the site setup in question.
The sites framework is most powerful where you use Site as the target of a ForeignKey or ManyToManyField so that you can link your model instances (i.e. records) to specific sites.

Mikes solution is correct if you want to have multiple sites with same apps with different content (sites module) on multiple domains or subdomains, but it has a drawback that you need to be running multiple instances of the Django process.
A better solution for the main problem about multiple domains or subdomains is to use a simple middleware that handles incoming requests with the process_request() function and changing the documented urlconf attribute (link) of the request object to the URLconf you want to use.
More details and an example of the per-request or per-domain URL dispatcher can be found at:
http://gw.tnode.com/0483-Django/

Try adding a wildcard subdomain: usually *.

Related

URL parameter before the domain name in Django

I want to configure my urls something like these:
username1.mysite.com
username2.mysite.com
You know, the parameter is actually the username, and its placed before the domain name. Other sites do this I have seen, for example, Wordpress Blogs and so on. Can I do this using Django URLs? Any help is appreciated.
I cannot think of a way to do this using Django's URLs because this is a subdomain NOT a URL parameter. What I would suggest is reading the subdomain in your server config (e.g nginx site config) and writing it into a header to be read by some custome middleware in django
I accomplished something like this with the "django-dynamicsites" plugin.
https://bitbucket.org/uysrc/django-dynamicsites
It's quite old and may need a few tweaks for modern Djangos but it does do what you need, I use it myself and it works well.
It involves modifying the django_sites table so doesn't play too nice with makemigrations. You may have to use the SQL to update the SQL database on your server to get around that.
I stumbled up django-subdomains which does exactly what I want. Thanks everyone.

Reversing urls in Django / Celery

I have been asked to send an email on friday with a list of projects matching a set of conditions. The database front end is written in Django and its an in house application. I would like to link to the admin page of the project in the email.
On my development machine I am trying
reverse("admin:index")
and I notice that it is only returning
admin
from the Celery task, whereas in standard Django views this would return
127.0.0.1:8000/admin/
Is there a way around this? I would prefer not to hard code the start of the urls.
I have set up Celery as described in the "first steps with Django" tutorial, and have a
myproject/myproject/celery.py
file defining the app (alongside settings.py and urls.py) and
project/myapp/tasks.py
file with the actual tasks.
reverse() always returns a domain-relative url, i.e. /admin/. One option to increase portability is to use the sites framework.
As you don't have a request object in your Celery task, you have to explicitly set the SITE_ID in your settings and set the site's name and domain in your database. Then you can do:
from django.contrib.sites.models import Site
url = "%s%s" % (Site.objects.get_current().domain, reverse('admin:index'))
Usually URLs in django are relative - i.e. the "127.0.0.1:8000" part you see when you hover the link comes from the fact that you are browsing the site from that location. Try looking at the href value of the URLs generated.
A simple solution to your problem is to concatenate the reverse output with the domain, i.e.
'http://example.com/'+reverse('admin:index')

How do I make Django figure out which Site object to use based on "Host" header in the HTTP request?

Consider a Django app built to serve multiple sites with slightly differing content using the standard Django sitesframework.
The traditional way to host this would be to configure multiple Site objects and setup the app in multiple Django projects with each project pointing to a different SITE_ID in their respective settings.py:s.
For various reasons I'd like to avoid having to create a new project for each new site. I want to be able to setup one project and have Django figure out which Site object to use based on the hostname referenced in the incoming HTTP request.
What is the recommended way to achieve this functionality?
Clarification: I want the site framework to ignore settings.SITE_ID (which is hard-coded in settings.py) and instead dynamically fetch Site objects based on what is in the Host header. Why this requirement? I'll be adding and removing sites multiple times per hour and the total amount of sites will exceed 10,000, so setting up a Django project for each site is not an option. Is this a problem that is solvable in Django? If so, what is the best way to achieve it?
The recommended way is to not attempt it at all, since settings should never change at runtime. Instead, set a variable in your virtual host configuration and have the WSGI adapter script or settings module pick one of the sites based on that.

Changing Django settings variable dynamically based on request for multiple site

Please advice whether is it correct method to change the urlconf and templatedir variables of a django settings file dynamically within a custom middleware function based on the site requested.
No. I don't know why you would want to do this. If you have multiple sites, the correct way to serve them is with multiple WSGI instances, each pointing at separate settings.py and urls.py files.
Edit after comment: This has nothing to do with the sites framework, which is completely optional. As I say, if you want to serve multiple sites, use multiple .wsgi scripts each pointing to a separate urls.py and settings.py. All the rest of the code can be the same.

django powering multiple shops from one code base on a single domain

I am new to django and python and am trying to figure out how to modify an existing app to run multiple shops through a single domain.
Django's sites middleware seems inappropriate in this particular case because it manages different domains, not sites run through the same domain, e.g. : domain.com/uk domain.com/us domain.com/es etc.
Each site will need translated content - and minor template changes. The solution needs to be flexible enough to allow for easy modification of templates.
The forms will also need to vary a bit, e.g minor variances in fields and validation for each country specific shop.
I am thinking along the lines of the following as a solution and would love some feedback from experienced django-ers:
In short: same codebase, but separate country specific urls files, separate templates and separate database
Create a middleware class that does IP localisation, determines the country based on the URL and creates a database connection, e.g. /au/ will point to the au specific database and so on.
in root urls.py have routes that point to a separate country specific routing file, e..g
(r'^au/',include('urls_au')),
(r'^es/',include('urls_es')),
use a single template directory but in that directory have a localised directory structure, e.g. /base.html and /uk/base.html and write a custom template loader that looks for local templates first. (or have a separate directory for each shop and set the template directory path in middleware)
use the django internationalisation to manage translation strings throughout
slight variances in forms and models (e.g. ZA has an ID field, France has 'door code' and 'floor' etc.) I am unsure how to handle these variations but I suspect the tables will contain all fields but allowing nulls and the model will have all fields but allowing nulls. The forms will to be modified slightly for each shop.
Anyway, I am keen to get feedback on the best way to go about achieving this multi site solution. It seems like it would work, but feels a bit "hackish" and I wonder if there's a more elegant way of getting this solution to work.
Thanks,
imanc
There's no reason you can't the sites framework with multiple Django installations served from different subdirectories under the same domain.
OK I have done some further digging and it seems that the Django sites framework is not suitable for the same domain but with different paths:
www.mydomain.com/uk
www.mydomain.com/au
etc.
The two other options are an apache/wsgi set up where a separate wsgi and settings.py is referenced for each subdirectory. This seems a bit cumbersome; I don't really want to have to be reconfiguring apache each time I deploy a new shop. Also it'd make maintaining the local dev, online dev, staging and live versions of the site more hassle.
I think given this situation the best solution is to look at a middleware class that keeps track of country code and somehow changes database settings and root urls.py. Then each app is going to have to be aware of its current base url for things like form actions and links and so on.