Search code examples
pythondjangodjango-contrib

Extending Django with sites app to provide current working app as SAAS


I have a working deployed Django application in production, with some users and various objects stored in the database. The client told me if the website could be replicated changing some minor things, such as templates, logos, etc. but maintaining some of the users and objects.

I had heard of django.contrib.sites long ago, so after reading the description it seemed the perfect choice. I went straight hands on, adding django.contrib.sites to the INSTALLED_APPS, putting the SITE_ID in my settings.py, and performing the migrations.

I chose to use a ManyToManyField for the sites, since the users might be able to login in one or more of the sites:

sites = models.ManyToManyField(Site)

Since I have modified managers for some models, like the User, I had to override my custom get_queryset, to only return the current site users, so I added the filter(sites=settings.SITE_ID) to the returned queryset, as I saw in the documentation:

from django.contrib.auth.models import BaseUserManager

class UserManager(BaseUserManager):

    def get_queryset(self):
        return super(UserManager, self).get_queryset().filter(
            is_active=True).filter(sites=settings.SITE_ID)

For other classes, since I didn't override the default manager, I just did override the objects:

objects = CurrentSiteManager()

Everything was working fine until I tried to test my current working app. Since the objects in the database do not have an associated site (the User.sites queryset is empty) I am not able to login with any user.

Thus, I have gone back, reverted the migrations (that take into account the modification of managers), and now I am in the initial state, before any site modification.

I have been trying to find documentation on how to approach this, but I have yet not found a tutorial or some good practices on how to perform this "initial" data migration for sites when there is data already in the DB.

My guess is that I have to perform the sites migrations, then assign the current (and only) working site to all the data (users, and related objects), then change the managers and run the managers migrations. Is that it? Or am I missing something?

Any help or insight would be very appreciated.


Solution

  • If I am understanding correctly, it sounds like the problem is that with your change, a user now MUST be tied to at least one site to be able to login. Since your current users are not associated with any sites, this creates the login issue.

    If this is the case, I would suggest adding a data migration after the schema migrations in your branch. This data migration would loop through all of the users and add settings.SITE_ID to user.sites. You will also want to create a function that does the opposite, removes the entry from user.sites in case you need to rollback, as described here.