128 lines
6.7 KiB
HTML
128 lines
6.7 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Tenant Tutorial{% endblock %}
|
|
|
|
{% block summary %}
|
|
<h1>Welcome to the Tenant Tutorial!</h1>
|
|
<h2>This interactive tutorial will teach you how to use <a href="https://github.com/bernardopires/django-tenant-schemas">django-tenant-schemas</a>.</h2>
|
|
{% endblock %}
|
|
|
|
{% block instructions %}
|
|
{% if need_sync %}
|
|
<h2>First Step: Sync your database</h2>
|
|
<p>Your database is empty, so the first step is to sync it. We only want to sync the <code>SHARED_APPS</code>.
|
|
For your convenience, here's the contents of <code>SHARED_APPS</code>:</p>
|
|
<ul>
|
|
{% for app in shared_apps %}
|
|
<li>{{ app }}</li>
|
|
{% endfor %}
|
|
</ul><br>
|
|
<p>Just run the command below on your shell to sync <code>SHARED_APPS</code>. Make sure your environment
|
|
has <code>Django</code> and <code>django-tenant-schemas</code> available.</p>
|
|
<pre>$ python manage.py migrate_schemas --shared</pre>
|
|
<p>When you're done refresh this page.</p>
|
|
{% elif no_public_tenant %}
|
|
<h2>Second Step: Create a public tenant</h2>
|
|
<h3>So how does django-tenant-schemas work?</h3>
|
|
<p><code>django-tenant-schemas</code> uses the request's hostname to try to find a tenant.
|
|
When a match is found,
|
|
<a href="http://www.postgresql.org/docs/8.1/static/ddl-schemas.html">PostgreSQL's search path</a>
|
|
is automatically set to be this tenant.</p>
|
|
<br>
|
|
<p>For this request, <code>django-tenant-schemas</code> couldn't find any tenant for the current address (<code>{{ hostname }}</code>).
|
|
When no tenant is found, <code>django-tenant-schemas</code> normally returns a <code>404</code>, but since
|
|
this is a tutorial and no tenant exists yet, we let it proceed.
|
|
<h3>Recommended Tenant's URLs Structure</h3>
|
|
<p>Let's assume you have your main website at <code>trendy-sass.com</code>. The recommended structure is
|
|
to put your tenants at subdomains, like <code>tenant1.trendy-sass.com</code>,
|
|
<code>tenant2.trendy-sass.com</code> and so forth.</p>
|
|
<h3>Creating the public tenant</h3>
|
|
<p><code>django-tenant-schemas</code> requires a tenant for all addresses you use, including your main website,
|
|
which we will from now on refer to as the public tenant.</p>
|
|
<br>
|
|
<p>Our model is called <code>Customer</code> and looks like this (taken from <code>models.py</code>):</p>
|
|
<pre>
|
|
class Client(TenantMixin):
|
|
name = models.CharField(max_length=100)
|
|
description = models.TextField(max_length=200)
|
|
created_on = models.DateField(auto_now_add=True)</pre>
|
|
<p>Let's create a tenant for our main website, located at <code>{{ hostname }}</code>. Open up a shell and enter the <code>django</code> shell:</p>
|
|
<pre>$ ./manage.py shell</pre>
|
|
<p>To create a tenant run the following commands:</p>
|
|
<pre>from customers.models import Client</pre>
|
|
<pre>
|
|
Client(domain_url='{{ hostname }}',
|
|
schema_name='public',
|
|
name='Trendy SaSS',
|
|
description='Public Tenant').save()</pre>
|
|
<p>Done! <code>django-tenant-schemas</code> will now be able to locate our public tenant and won't return 404. Refresh this page to see the next step.</p>
|
|
{% elif only_public_tenant %}
|
|
<h2>Third Step: Create Tenants</h2>
|
|
<p>We've already created the public tenant, now it's time to create some tenants for subdomains. I assume you're running this on your local machine,
|
|
so the easiest way to simulate domains is to edit your <a href="http://en.wikipedia.org/wiki/Hosts_(file)"><code>hosts</code> file</a>.
|
|
<a href="http://www.rackspace.com/knowledge_center/article/how-do-i-modify-my-hosts-file">Here are instructions for all platforms</a>.
|
|
I'll assume you're on Linux.</p>
|
|
<pre>$ sudo nano /etc/hosts </pre>
|
|
<p>Add the following lines:</p>
|
|
<pre>
|
|
127.0.0.1 tenant1.trendy-sass.com
|
|
127.0.0.1 tenant2.trendy-sass.com</pre>
|
|
<p>We're basically tricking our computer to think both <code>tenant1.trendy-sass.com</code> and <code>tenant2.trendy-sass.com</code> point to <code>127.0.0.1</code>.
|
|
Once you're done, try visiting <a href="http://tenant1.trendy-sass.com:8000">tenant1.trendy-sass.com</a>,
|
|
you should get a django <code>404</code>. As we have previously mentioned, we don't have a tenant there yet, so a <code>404</code> will be thrown.<br></p>
|
|
<br>
|
|
<p>We can now add tenants using these URLs and our project will be able to find them and identify them as our tenants. Back to the django shell:</p>
|
|
|
|
<pre>$ ./manage.py shell</pre>
|
|
<pre>from customers.models import Client</pre>
|
|
<pre>
|
|
Client(domain_url='tenant1.trendy-sass.com',
|
|
schema_name='tenant1',
|
|
name='Tenant1 - Awesome',
|
|
description='Our first real tenant, awesome!').save()</pre>
|
|
<p>Saving a tenant that didn't exist before will create their schema and sync <code>TENANT_APPS</code> automatically. You should see
|
|
the following lines as the result.</p>
|
|
{% if DJANGO17 %}<pre>Operations to perform:
|
|
Synchronize unmigrated apps: customers, tenant_schemas
|
|
Apply all migrations: contenttypes, auth, sessions
|
|
Synchronizing apps without migrations:
|
|
Creating tables...
|
|
Installing custom SQL...
|
|
Installing indexes...
|
|
Running migrations:
|
|
Applying contenttypes.0001_initial... OK
|
|
Applying auth.0001_initial... OK
|
|
Applying sessions.0001_initial... OK</pre>
|
|
{% else %}<pre>=== Running syncdb for schema: tenant1
|
|
Creating tables ...
|
|
Creating table auth_permission
|
|
Creating table auth_group_permissions
|
|
Creating table auth_group
|
|
Creating table auth_user_groups
|
|
Creating table auth_user_user_permissions
|
|
Creating table auth_user
|
|
Creating table django_content_type
|
|
Installing custom SQL ...
|
|
Installing indexes ...
|
|
Installed 0 object(s) from 0 fixture(s)</pre>
|
|
{% endif %}
|
|
<p>This means your tenant was installed successfully. Now create the second tenant.</p>
|
|
<pre>
|
|
Client(domain_url='tenant2.trendy-sass.com',
|
|
schema_name='tenant2',
|
|
name='Tenant2 - Even Awesome-r',
|
|
description='A second tenant, even more awesome!').save()</pre>
|
|
|
|
<p>Now try visiting <a href="http://tenant1.trendy-sass.com:8000">tenant1.trendy-sass.com</a> and
|
|
<a href="http://tenant2.trendy-sass.com:8000">tenant2.trendy-sass.com</a> or refresh this page.</p>
|
|
{% else %}
|
|
<h2>Tutorial Complete!</h2>
|
|
<p>Well done, you have completed the tutorial! Use the bottom menu to see your tenants.</p>
|
|
<h3>Where to go from here</h3>
|
|
<p>There are some interesting features that we did not cover.</p>
|
|
<ul>
|
|
<li><a href="https://django-tenant-schemas.readthedocs.io/en/latest/install.html#tenant-view-routing">Tenant View-Routing</a>. Serve different views for the same path. (this tutorial makes use of this feature)</li>
|
|
<li><a href="https://django-tenant-schemas.readthedocs.io/en/latest/use.html#management-commands">Management Commands</a>. Run a command for a particular tenant.</li>
|
|
</ul>
|
|
{% endif %}
|
|
{% endblock %}
|