简体   繁体   中英

Filter django query set by a non-database operation

Working with ReviewBoard 1.6.11, which uses Django 1.3.3. There is a RepositoryManager class that has a method called 'accessible', defined as this:

class RepositoryManager(Manager):
    def accessible(self, user, visible_only=True, local_site=None):
        """Returns repositories that are accessible by the given user."""
        if user.is_superuser:
            qs = self.all()
        else:
            q = Q(public=True)

            if visible_only:
                q = q & Q(visible=True)

            if user.is_authenticated():
                q = q | (Q(users__pk=user.pk) |
                         Q(review_groups__users=user.pk))

            qs = self.filter(q).distinct()

        return qs.filter(local_site=local_site)

The problem is that I want to filter the results of this query by something else that does not interact with the database (filesystem permissions of the user). accessible() needs to return a QuerySet, though. Otherwise, I would just create a list and populate it with the appropriate items from the result.

I'm fairly new to Django. Is this a reasonable thing to do, or am I going about this all wrong?

I was able to solve this by creating a QuerySet subclass like so:

class RepositoryQuerySet(QuerySet):
    def __init__(self, *args, **kwargs):
        super(RepositoryQuerySet, self).__init__(*args, **kwargs)
        self._user_filter = None

    def _clone(self, *args, **kwargs):
        retval = super(RepositoryQuerySet, self)._clone(*args, **kwargs)
        retval._user_filter = self._user_filter
        return retval

    def filter_by_user_access(self, user):
        self._user_filter = user.username

    def iterator(self):
        for repo in super(RepositoryQuerySet, self).iterator():
            if self._user_filter is None:
                yield repo
                continue
            # ...logic for restricting access by user...
            # If user has access, just yield repo.  If not, just 'continue'

Then in RepositoryManager.accessible, right after the call to distinct(), call:

            qs.filter_by_user_access(user)

Finally, for the manager to use the new query set class, create:

    def get_query_set(self):
        return RepositoryQuerySet(self.model, using=self.db)

in the RepositoryManager class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM