Login

SelfForeignKey to prevent hierarchical loops

Author:
jamesgpearce
Posted:
February 1, 2010
Language:
Python
Version:
1.1
Score:
0 (after 0 ratings)

When you have a model containing a field that is a foreign key back to the same model, you could find yourself with a hierarchy with an infinite loop:

Data modelling Back to the Future

grandfather > father > son > father > ...

Using this field instead of the standard ForeignKey will ensure that no model instance is saved that has itself as an ancestor, breaking the relationship if it does.

(Enhancements: I am sure one would want to better enhance this with appropriate error handling instead of silently disconnecting the relationship. And the relevant forms ought not show ancestors in the field's widget to reduce the chances of this happening in the first place.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class SelfForeignKey(models.ForeignKey):
    def pre_save(self, instance, add):
        manager = instance.__class__.objects
        ancestor_id = getattr(instance, self.attname)
        while ancestor_id is not None:
            if ancestor_id == instance.id:
                return None
            ancestor = manager.get(id=ancestor_id)
            ancestor_id = getattr(ancestor, self.attname)
        return getattr(instance, self.attname)

# used like this:

class Category(models.Model):
    name = models.CharField(max_length=20)
    parent = SelfForeignKey('self', related_name='child_category_set', ...)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 4 weeks ago

Comments

Please login first before commenting.