views:

70

answers:

2

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.

+1  A: 

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.

Mike DeSimone
I have not, thanks. I will dig into it, but could you quickly elaborate how those pieces fit together?
Björn Lilja
I don't think that does the trick... Writing a middleware class that fetches the subdomain could work, but not sure how to force that into matching the pattern in urls.py eg cat.site.com needs to match /^cat/(?P<cat_slug>([^/]+))/ and hence be rewritten somehow
Björn Lilja
The point is not to pass the site info via URL, but by `from settings import SITE_ID` or `os.environ.get('SITE_ID', 1)`. I think any attempt to put a hostname component in a URL pattern will not work out. Even if you get Apache to do rewrites for you, the URLs generated by `reverse` will *not* be the ones you want, but instead the rewritten ones.
Mike DeSimone
OK, so let's say that i'm configuring one SITE for each subdomain. that will give me the correct full url when calling reverse etc. This still leaves me with the problem that I am exposing the "category" in the path which it not what I want.
Björn Lilja
Your solution solves half the problem, thanks! Combined with a somewhat dynamic urlconf and a middleware process_view function that injects the A parameter (fetched from the site/subdomain) that would be missing. But it's messy...
Björn Lilja
Exposing the "category"? Your description isn't clear enough for me. If you don't want "category" in the URL, just leave it out. So long as you can write a regexp for the path, and it doesn't violate HTTP's URL rules, it can be a URL.
Mike DeSimone
I should clarify my concern. When you say "http://site.com/category/A/product/B/", you aren't telling us which of "category", "A", "product", and/or "B" are parameters and which are literal text.
Mike DeSimone
Sorry. A and B are parameters, "category" and "product" are only descriptive texts. So what I really mean is that i don't want to expose A in the URL.
Björn Lilja
But, in the example of "http://A.site.com/product/B", you're exposing it in the hostname...?
Mike DeSimone
A: 

Try adding a wildcard subdomain: usually *.

aharon