from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured from django.core.paginator import Paginator from django.db.models import QuerySet class RestrictedViewMixin: """ This mixin overrides two helpers in order to pass the user object to the filters. get_queryset alters the objects returned for list views. get_form_kwargs passes the request object to the form class. Remaining permissions checks are in forms.py """ allow_empty = True queryset = None model = None paginate_by = None paginate_orphans = 0 context_object_name = None paginator_class = Paginator page_kwarg = "page" ordering = None def set_extra_args(self, user): """ This function is overriden to filter the objects by the requesting user. """ self.extra_permission_args = {} def get_queryset(self, **kwargs): """ This function is overriden to filter the objects by the requesting user. """ self.set_extra_args(self.request.user) if self.queryset is not None: queryset = self.queryset if isinstance(queryset, QuerySet): # queryset = queryset.all() queryset = queryset.filter( user=self.request.user, **self.extra_permission_args ) elif self.model is not None: queryset = self.model._default_manager.filter( user=self.request.user, **self.extra_permission_args ) else: raise ImproperlyConfigured( "%(cls)s is missing a QuerySet. Define " "%(cls)s.model, %(cls)s.queryset, or override " "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__} ) if hasattr(self, "get_ordering"): ordering = self.get_ordering() if ordering: if isinstance(ordering, str): ordering = (ordering,) queryset = queryset.order_by(*ordering) return queryset def get_form_kwargs(self): """Passes the request object to the form class. This is necessary to only display members that belong to a given user""" kwargs = super().get_form_kwargs() kwargs["request"] = self.request return kwargs class RestrictedFormMixin: """ This mixin is used to restrict the queryset of a form to the current user. The request object is passed from the view. Fieldargs is used to pass additional arguments to the queryset filter. """ fieldargs = {} # TODO: implement set_extra_args to check more permissions here # for completeness, however as views open forms, the permissions # are already checked there, so it may not be necessary. def __init__(self, *args, **kwargs): # self.fieldargs = {} self.request = kwargs.pop("request") super().__init__(*args, **kwargs) for field in self.fields: # Check it's not something like a CharField which has no queryset if not hasattr(self.fields[field], "queryset"): continue model = self.fields[field].queryset.model # Check if the model has a user field try: model._meta.get_field("user") # Add the user to the queryset filters self.fields[field].queryset = model.objects.filter( user=self.request.user, **self.fieldargs.get(field, {}) ) except FieldDoesNotExist: pass