Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override default queryset in Django admin

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

class NondeletedManager(models.Manager):
    """Returns only objects which haven't been deleted"""

    def get_query_set(self):
        return super(NondeletedManager, self).get_query_set().exclude(deleted=True)

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

How can I override the default queryset used by Django admin module to include deleted conversations?

like image 207
Natan Yellin Avatar asked Sep 10 '12 14:09

Natan Yellin


People also ask

Is Django QuerySet lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.

What does QuerySet []> mean?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.

What is __ in Django ORM?

In Django, above argument is called field lookups argument, the field lookups argument's format should be fieldname__lookuptype=value. Please note the double underscore ( __ ) between the field name(depe_desc) and lookup type keyword contains.

What is a QuerySet?

A QuerySet represents a collection of objects from your database. It can have zero, one or many filters. Filters narrow down the query results based on the given parameters. In SQL terms, a QuerySet equates to a SELECT statement, and a filter is a limiting clause such as WHERE or LIMIT .


3 Answers

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.

like image 57
Konrad Hałas Avatar answered Oct 03 '22 05:10

Konrad Hałas


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
like image 10
Natan Yellin Avatar answered Oct 03 '22 03:10

Natan Yellin


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.

like image 5
zlovelady Avatar answered Oct 03 '22 03:10

zlovelady