Login

ParentModel and ChildManager for Model Inheritance

Author:
jpwatts
Posted:
September 8, 2008
Language:
Python
Version:
1.0
Score:
9 (after 9 ratings)

This is the approach I've taken to access instances of child models from their parent. Functionally it's very similar to snippets 1031 and 1034, but without the use of django.contrib.contenttypes.

Usage:

class Post(ParentModel):
    title = models.CharField(max_length=50)

    objects = models.Manager()
    children = ChildManager()

    def __unicode__(self):
        return self.title

    def get_parent_model(self):
        return Post

class Article(Post):
    text = models.TextField()

class Photo(Post):
    image = models.ImageField(upload_to='photos/')

class Link(Post):
    url = models.URLField()

In this case, the Post.children manager will return a queryset containing instances of the appropriate child model, rather than instances of Post.

>>> Post.objects.all()
[<Post: Django>, <Post: Make a Tumblelog>, <Post: Self Portrait>]

>>> Post.children.all()
[<Link: Django>, <Article: Make a Tumblelog>, <Photo: Self Portrait>]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from django.db import models
from django.db.models.query import QuerySet


class ChildQuerySet(QuerySet):
    def iterator(self):
        for obj in super(ChildQuerySet, self).iterator():
            yield obj.get_child_object()


class ChildManager(models.Manager):
    def get_query_set(self):
        return ChildQuerySet(self.model)


class ParentModel(models.Model):
    _child_name = models.CharField(max_length=100, editable=False)

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        self._child_name = self.get_child_name()
        super(ParentModel, self).save(*args, **kwargs)

    def get_child_name(self):
        if type(self) is self.get_parent_model():
            return self._child_name
        return self.get_parent_link().related_query_name()

    def get_child_object(self):
        return getattr(self, self.get_child_name())

    def get_parent_link(self):
        return self._meta.parents[self.get_parent_model()]

    def get_parent_model(self):
        raise NotImplementedError

    def get_parent_object(self):
        return getattr(self, self.get_parent_link().name)

More like this

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

Comments

donspaulding (on September 8, 2008):

Nice.

1031 and 1034 solved the problem, but this was the usage I was looking to get from the solution. Thanks!

#

neithere (on November 2, 2008):

Thanks, excellent snippet!

#

carljm (on February 5, 2009):

Slick.

#

BUZZY (on December 3, 2012):

That's exactly what I was looking for, thanks!

#

Please login first before commenting.