Override default queryset in Django admin

前端 未结 6 2064
孤城傲影
孤城傲影 2020-11-27 14:51

One of my models has a deleted flag, which is used to hide objects globally:

class NondeletedManager(models.Manager):
    \"\"\"Returns only objects which ha         


        
相关标签:
6条回答
  • 2020-11-27 15:17

    You can do this with a Django proxy model.

    # models.py
    class UnfilteredConversation(Conversation):
        class Meta:
            proxy = True
    
        # this will be the 'default manager' used in the Admin, and elsewhere
        objects = models.Manager() 
    
    # admin.py
    @admin.register(UnfilteredConversation)
    class UnfilteredConversationAdmin(Conversation):
        # regular ModelAdmin stuff here
        ...
    

    Or, if you have an existing ModelAdmin class you want to re-use:

    admin.site.register(UnfilteredConversation, ConversationAdmin)
    

    This approach avoids issues that can arise with overriding the default manager on the original Conversation model - because the default manager is also used in ManyToMany relationships and reverse ForeignKey relationships.

    0 讨论(0)
  • 2020-11-27 15:19

    The accepted solution works great for me but I needed a little bit more flexibility, so I ended up extending the changelist view to add in a custom queryset parameter. I can now configure my default queryset/filter as such and it can still be modified by using a different filter (get parameters):

    def changelist_view(self, request, extra_context=None):
        if len(request.GET) == 0 :
            q = request.GET.copy()
            q['status__gt'] = 4
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
    
        return super(WorksheetAdmin,self).changelist_view(request, extra_context=extra_context)
    
    0 讨论(0)
  • 2020-11-27 15:22

    Natan Yellin is correct, but you can change the managers order and the first will be the default, then it is the used by the admin:

    class Conversation(BaseModel):
        ...
        deleted = models.BooleanField(default=False)
    
        all_conversations = models.Manager() # includes deleted conversations
        objects = NondeletedManager()
    

    The admin implementation of get_queryset() use ._default_manager instead .objects, as show next

    qs = self.model._default_manager.get_queryset()
    

    ref Django github BaseModelAdmin implementation

    This only ensures that every time you use YourModel.objects, you will not include deleted objects, but the generic views and others uses ._default_manager too. Then if you don't override get_queryset is not a solution. I've just check on a ListView and admin.

    0 讨论(0)
  • 2020-11-27 15:25

    Konrad is correct, but this is more difficult than the example given in the documentation.

    Deleted conversations can't be included in a queryset that already excludes them. So I don't see an option other than re-implementing admin.ModelAdmin.queryset entirely.

    class ConversationAdmin (admin.ModelAdmin):
    
        def queryset (self, request):
            qs = Conversation.all_conversations
            ordering = self.get_ordering(request)
            if ordering:
                qs = qs.order_by(*ordering)
            return qs
    
    0 讨论(0)
  • 2020-11-27 15:26

    You can override get_queryset method in your model admin class.

    class MyModelAdmin(admin.ModelAdmin):
        def get_queryset(self, request):
            qs = super(MyModelAdmin, self).get_queryset(request)
            if request.user.is_superuser:
                return qs
            return qs.filter(author=request.user)
    

    Note in Django<=1.5 the method was named just queryset.

    0 讨论(0)
  • 2020-11-27 15:40

    What would be so wrong with the following:

    class Conversation(BaseModel):
        ...
        deleted = models.BooleanField(default=False)
        objects = models.Manager() # includes deleted conversations
        nondeleted_conversations = NondeletedManager()
    

    So in your own apps/projects, you use Conversation.nondeleted_conversations() and let the built-in admin app do it's thing.

    0 讨论(0)
提交回复
热议问题