Question

I've got custom save() method which check my object's "active" field is equal 2 and then give the same number to all descendant fields (using MPTT)

def save(self):
  if self.active == 2:
  self.get_descendants().update(active=2)

  super(Post, self).save()

Now i want to this code work also when i update() my model. Should I try to make custom update method? How to do it?

Was it helpful?

Solution

An easy fix would be to do the original update, and then using get_queryset_descendants() do an additional update for all descendants. Full code would like this:

qs = <some queryset>
qs.update(**values)
descendants = MyModel.objects.get_queryset_descendants(qs.filter(active=2))
descendants.update(active=2)

Or if you only want to update the active attribute, it can be done in a single go:

qs = <some queryset>
descendants = MyModel.objects.get_querset_descendants(qs, include_self=True)
descendants.update(active=2)

This can of course be wrapped in the update function. That would look like this:

from django.db import transaction
from django.db.models.query import QuerySet

class MyModelQuerySet(QuerySet):
    def update(self, **kwargs):
        with transaction.atomic(): # for Django >= 1.6
        ####### OR ######
        with transaction.commit_on_succes(): # for Django <= 1.5
            r = super(MyModelQuerySet, self).update(**kwargs)
            descendants = self.model.objects.get_query_set_descendants(self.filter(active=2))
            descendants.update(active=2)
        return r

The with transaction.atomic() or with transaction.commit_on_succes() prevents the first update from saving if the second update fails, this is to ensure integrity on a database level should something go wrong in the second update.

You should check the documentation for your current version of Django on how to use a custom queryset with custom managers (that is mppt.managers.TreeManager).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top