Django Manager Chaining

前端 未结 4 2094
独厮守ぢ
独厮守ぢ 2021-01-30 09:19

I was wondering if it was possible (and, if so, how) to chain together multiple managers to produce a query set that is affected by both of the individual managers. I\'ll expla

4条回答
  •  夕颜
    夕颜 (楼主)
    2021-01-30 09:54

    Here is the specific solution to my problem using the custom QuerySetManager by Simon that Scott linked to.

    from django.db import models
    from django.contrib import admin
    from django.db.models.query import QuerySet
    from django.core.exceptions import FieldError
    
    class MixinManager(models.Manager):    
        def get_query_set(self):
            try:
                return self.model.MixinQuerySet(self.model).filter(deleted=False)
            except FieldError:
                return self.model.MixinQuerySet(self.model)
    
    class BaseMixin(models.Model):
        admin = models.Manager()
        objects = MixinManager()
    
        class MixinQuerySet(QuerySet):
    
            def globals(self):
                try:
                    return self.filter(is_global=True)
                except FieldError:
                    return self.all()
    
        class Meta:
            abstract = True
    
    class DeleteMixin(BaseMixin):
        deleted = models.BooleanField(default=False)
    
        class Meta:
            abstract = True
    
        def delete(self):
            self.deleted = True
            self.save()
    
    class GlobalMixin(BaseMixin):
        is_global = models.BooleanField(default=True)
    
        class Meta:
            abstract = True
    

    Any mixin in the future that wants to add extra functionality to the query set simply needs to extend BaseMixin (or have it somewhere in its heirarchy). Any time I try to filter the query set down, I wrapped it in a try-catch in case that field doesn't actually exist (ie, it doesn't extend that mixin). The global filter is invoked using globals(), while the delete filter is automatically invoked (if something is deleted, I never want it to show). Using this system allows for the following types of commands:

    TemporaryModel.objects.all() # If extending DeleteMixin, no deleted instances are returned
    TemporaryModel.objects.all().globals() # Filter out the private instances (non-global)
    TemporaryModel.objects.filter(...) # Ditto about excluding deleteds
    

    One thing to note is that the delete filter won't affect admin interfaces, because the default Manager is declared first (making it the default). I don't remember when they changed the admin to use Model._default_manager instead of Model.objects, but any deleted instances will still appear in the admin (in case you need to un-delete them).

提交回复
热议问题