Override base filter for model's queryset (Django 1.6)?

224 views
Skip to first unread message

Derek

unread,
Jan 14, 2017, 2:21:44 PM1/14/17
to django-users
I am looking for help with a Django 1.6 application.

The use case is not too complicated; I need to override the delete method for
the queryset to prevent some records being removed by the bulk delete (run via
the admin interface); and I also want to override the base filter for the model's
queryset to limit what is displayed.

Preventing the deletion works well; but I cannot see how to override the base 
filter for the model - below are some examples of code I have tried that do not
work.

I am sure this is not hard, but I cannot find the correct syntax.

Any ideas appreciated.

Thanks
Derek


```
from django.db.models import Model, Manager
from django.db.models import AutoField, CharField
from django.db.models.query import QuerySet


class MyModelQuerySet(QuerySet):

    # NEED to override the base filter for this model ???

    """
    def __init__(self, *args, **kwargs):
        super(MyModelQuerySet, self).__init__(*args, **kwargs)
        # does not filter at all?
        self.queryset = models.Site.objects.filter(
            classification='general')

    def filter(self):
        # just gives errors!
        return self.queryset.filter(classification='special')
    """
    
    def delete(self, *args, **kwargs):
        for obj in self:
            if obj.code != 'protected':
                obj.delete()


class MyModelManager(Manager):

    def get_queryset(self):
        return MyModelQuerySet(model=self.model, using=self._db)


class MyModel(Model):
    id = AutoField(primary_key=True)
    name = CharField(
        unique=True,
        max_length=50,)
    code = CharField(
        unique=True,
        max_length=250)
    classification = CharField(
        max_length=100)
    objects = MyModelManager()
```

Melvyn Sopacua

unread,
Jan 14, 2017, 2:58:15 PM1/14/17
to django...@googlegroups.com

On Saturday 14 January 2017 21:20:32 Derek wrote:

> and I also want to override the base filter for

> the model's

> queryset to limit what is displayed.

 

This is covered in the Manager documentation in detail.

 

--

Melvyn Sopacua

Derek

unread,
Jan 15, 2017, 9:53:11 AM1/15/17
to Django users
Hi Melvyn

You don't appear to have understood my question; and I did not see this particular use case covered in the docs (which is why I asked it). You also pointed me to the wrong version; in particular "QuerySet.as_manager()" is not method in 1.6.

Melvyn Sopacua

unread,
Jan 15, 2017, 11:52:47 AM1/15/17
to django...@googlegroups.com
Hi Derek,

On Sunday 15 January 2017 06:53:10 Derek wrote:

> You don't appear to have understood my question; and I did not see
> this particular use case covered in the docs (which is why I asked
> it). You also pointed me to the wrong version; in particular
> "QuerySet.as_manager()" is not method in 1.6.

Take a look at the DahlBookManager example: it filters all books by
author Dahl and "limits what is displayed".
If you compare it to your code, then you see that the entire
MyModelQuerySet class can be deleted and your
MyModelManager.get_queryset() method turns into:

def get_queryset(self):
return super(MyModelManager, self).get_queryset().filter(
classification='general'
)

Delete method could become something like this:

def delete(self):
qs = super(MyModelManager, self).get_queryset().filter(
code__neq='protected'
)
return qs.delete()

I'm using a call to super() in delete, so we get access to all objects.
Please read the part about the default manager and its dangers before
making it the default manager.

Last, but certainly not least: if you *only* need this for the admin,
then it's better to look at ModelAdmin's list_filter property and/or
get_queryset method and the has_delete_permission method. For example:

class MyModelAdmin(admin.ModelAdmin):
model = MyModel
list_filter = ('classification',)

def has_delete_permission(self, req, obj):
if super(MyModelAdmin, self).has_delete_permission(req, obj):
if obj.code != 'protected' :
return True
return False

Note that this doesn't set the default filter to 'general', but it does
make filtering transparent (and allows access to objects which are not
'general').

P.S.: The reason I pointed to 1.10 docs is simple: 1.6 is no longer
supported by the Django Project and it's documentation has been removed
from the site.

--
Melvyn Sopacua
Reply all
Reply to author
Forward
0 new messages