fabiocaccamo / django-admin-interface

:superhero: :zap: django's default admin interface with superpowers - customizable themes, popup windows replaced by modals and many other features.
MIT License
1.8k stars 180 forks source link

Multi tenancy support #389

Open kennylajara opened 4 months ago

kennylajara commented 4 months ago

Hi! Thank you amazing package!

Now, for the want to use different themes based on the Django site being visited.

I know this is currently not supported. But I'm opening this ticked because I saw someone asked the same in this Issue and when you asked if he is using Django Sites, you suggested it could be easy if he is using it. Unfortunately, he wasn't said no. As I am using it, it would be awesome nice to find a solution or workaround.

Upvote & Fund

Fund with Polar

fabiocaccamo commented 4 months ago

@kennylajara as explained in #242, it should be relatively easy to achieve this by:

  1. extending ThemeQuerySet
  2. overriding get_active method (here you decide the theme to return)
  3. setting the customized queryset as default objects manager for the Theme model.

If you will come back with a reusable solution I will be glad to look at it!

kennylajara commented 4 months ago

I can think on using something like this to determine if the Site framework is being used:

from django.conf import settings

def is_sites_app_installed():
    if 'django.contrib.sites' in settings.INSTALLED_APPS:
        try:
            from django.contrib.sites.models import Site
            return True
        except ImportError:
            return False
    return False

Extend the Theme model to add this property:

    site = models.PositiveSmallIntegerField(  # it can be a FK too
        blank=True,
        default=1,
        verbose_name=_("site"),
    )

And change the QuerySet to this:

class ThemeQuerySet(models.QuerySet):
    def get_active(self):
        using_sites_framework = is_sites_app_installed()

        if using_sites_framework:
            objs_active_qs = self.filter(active=True, site=Site.objects.get_current().id)  # `Site.objects.get_current()` is `site` is a FK
        else:
            objs_active_qs = self.filter(active=True)

        objs_active_ls = list(objs_active_qs)
        objs_active_count = len(objs_active_ls)

        if objs_active_count == 0:
            obj = self.all().first()
            if obj:
                obj.set_active()
            else:
                obj = self.create()

        elif objs_active_count == 1:
            obj = objs_active_ls[0]

        elif objs_active_count > 1:
            obj = objs_active_ls[-1]
            obj.set_active()

        return obj

But I think it will still require a way to handle sites that are added and have not set any Theme yet. It might be a way to mark a theme as default or something else.

kennylajara commented 4 months ago

Would that work for you? I really need this feature, so, I'm willing to develop it with you guidance.

fabiocaccamo commented 4 months ago

@kennylajara it's hard to give help based on code snippets pasted here, I would suggest you to work on your own solution that works well for your use case and that is enough generic to fit other people needs, then submit a PR.