﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
7296	Overriding `get_query_set()` on default manager requires care	scott@…	nobody	"I had a model where objects was a custom manager that filtered so only models marked ""active"" were returned.  It looks like:

{{{
class ClubManager(models.Manager):
    def get_query_set(self):
        return super(ClubManager, self).get_query_set().filter(active=True)

class Club(models.Model):
    ...
    active = models.BooleanField(default=False)
    
    objects = ClubManager()
    ...
}}}

It used to work fine, but I think the queryset-refactor merge has changed that.  I had a unit test like:

{{{
    club = Club.objects.create(name='Drunken Clam')
    ...
    club.active = True
    club.save()
}}}

It started to fail on the call to save() because of a duplicate primary key.  It was trying to insert the same record twice.

The culprit is in django.db.models.base.py Model class save_base() method (from line 305):

{{{
        manager = cls._default_manager
        if pk_set:
            # Determine whether a record with the primary key already exists.
            if manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by():
}}}

This is SVN r7547.

On the call to create() the record is inserted in the db.  On the subsequent call to save() it checks the default manager for the pk.  The default manager filters out the recently inserted model because it has active=False.  A record with the pk is not found, so it tries to insert it again and gets a pk conflict.

Not sure if you consider this a bug.  If not, it seems like a new constraint that the default manager must not filter the queryset.

Thanks.

Scott"		closed	Database layer (models, ORM)	dev		invalid	default manager, queryset refactor, filter, primary key		Unreviewed	0	0	0	0	0	0
