Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django, Custom Managers affect save method?

I'm using Django 1.7. I've got a default custom manager that filters on an "active" boolean field. According to the docs, it needs to be the default manager to work with related fields (ie. accessing User.story_set only shows active Story objects). I'm keeping the standard manager for admin and shell access, but I am unable to save changes to objects, I'm speculating because save() methods pass through the default manager at some point.

class Story(models.Model):
    active = models.BooleanField(default=True)
    ....

    objects = ActiveStoryManager()
    full_set = models.Manager()

class ActiveStoryManager(models.Manager):
    def get_query_set(self):
        return super(ActiveStoryManager, self).get_query_set().filter(active=True)
    use_for_related_fields = True

This works well for all public-facing use. However, in admin and shell I am unable to affect inactive objects, including turning them back active.

story = Story.full_set.get(id=#) will fetch a story with active=False, but after setting active=True I am unable to save, getting a

django.db.utils.IntegrityError: duplicate key value violates unique constraint "stories_story_pkey" DETAIL: Key (id)=(#) already exists.

Calling save.(force_update=True) returns django.db.utils.DatabaseError: Forced update did not affect any rows.

So while save() is a model method, it seems to depend on the default manager at some point in the saving process.

A workaround is using the Queryset API, e.g. Story.full_set.filter(id=#).update(active=True), but that's only usable in the shell, and requires manually typing each change, still can't save inactive instances in the admin.

Any help on this?

like image 754
sybaritic Avatar asked Nov 23 '14 05:11

sybaritic


1 Answers

It cannot be done! As inancsevinc pointed out, save() calls on the default manager. The Django docs mention that get_query_set should not be modified on default managers, and I have sadly found out why. Hopefully in the future relatedManagers can be specified/controlled, but for now this method will not work for me. Confirmed in Django IRC chat.

Instead, I'm throwing together a ordinary Manager method, as well as model methods for some models, to get equivalent functionality. Also requires changing all the related_set calls in the template to include the new methods, so it's a pain, but no other way.

like image 66
sybaritic Avatar answered Sep 30 '22 16:09

sybaritic