import logging from django.apps import apps from django.conf import settings from django.contrib.auth import get_user_model from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import ugettext_lazy as _, ugettext logger = logging.getLogger("basetheme_bootstrap") def get_user_preference_class(): if cache.get("has_no_user_preferences_model", False): return None if not getattr(settings, "BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_ENABLED", False): cache.set("has_no_user_preferences_model", True, None) return None try: return apps.get_model( app_label=getattr(settings, "BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_LOCATION_APP", "your_app"), model_name=getattr(settings, "BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_NAME", "UserPreferences"), ) except LookupError as e: logging.error("Either create the UserPreferences model, " "or set BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_ENABLED to False") cache.set("has_no_user_preferences_model", True, None) return None def get_user_preferences_for_user(user): if cache.get("has_no_user_preferences_model", False): return None klass = get_user_preference_class() if klass is None: return None return klass.get_for_user(user=user) class UserPreferencesAbstractModelWithUser(models.Model): class Meta: abstract = True @classmethod def get_for_user(cls, user): try: pref = cls.objects.get(user=user) except cls.MultipleObjectsReturned: for p in cls.objects.filter(user=None)[1:]: p.delete() pref = cls.objects.get(user=user) except TypeError: return cls.get_for_user(None) except cls.DoesNotExist: try: pref, _ = cls.objects.get_or_create(user=None) except cls.MultipleObjectsReturned: for p in cls.objects.filter(user=None)[1:]: p.delete() pref, _ = cls.objects.get(user=None) if user is not None: pref.pk = None pref.id = None pref.user = user pref.save() return pref def full_clean(self, **kwargs): # Checking for coherency on default preferences (user is None) if self.user is None: try: default_pref = self.__class__.objects.get(user=None) if default_pref.id != self.id: raise ValidationError('Can\'t have more than one default preferences object, specify a user.') except self.__class__.DoesNotExist: pass return super().full_clean(**kwargs) def save(self, *args, **kwargs): self.full_clean() return super().save(*args, **kwargs) def __str__(self): return ugettext("Default preferences") if self.user is None else '%s (%s)' % ( self.user.username, self._meta.verbose_name.title(), ) @classmethod def get_allowed_fields(cls): if cls.preferences_groups is not None: for group, fields in cls.preferences_groups.items(): for f in fields: yield f return for field_name in [f.name for f in cls._meta.get_fields()]: if field_name == "id" or field_name == "pk" or field_name == "user": continue yield field_name @classmethod @property def preferences_groups(cls): return None @property def preferences_groups_descriptions(self): return {}