Skip to content

Instantly share code, notes, and snippets.

@craigds
Last active December 26, 2015 04:08
Show Gist options
  • Save craigds/7090434 to your computer and use it in GitHub Desktop.
Save craigds/7090434 to your computer and use it in GitHub Desktop.
our mptt category model that stores materialized URL for lookups
from fieldsignals import post_save_changed
from mptt.models import MPTTModel
class Category(MPTTModel):
parent = models.ForeignKey('self', null=True, blank=True, db_index=True)
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, db_index=True)
url = models.CharField(max_length=256, unique=True, db_index=True)
class MPTTMeta:
order_insertion_by = ('slug',)
class Meta:
verbose_name_plural = _('categories')
unique_together = (('parent', 'name'), ('parent', 'slug'))
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
return super(Category, self).save(*args, **kwargs)
def update_url(self):
if self.parent:
url = '%s/%s' % (self.parent.url, self.slug)
else:
url = self.slug
if url == self.url:
return
# update url without trigger save() (avoid infinite recursion in post-save handler)
self.url = url
Category.objects.filter(pk=self.pk).update(url=url)
# cascade to descendants
cursor = connection.cursor()
count = 1
level = self.level
while count:
level += 1
sql = """
UPDATE "tags_category" SET url = (
SELECT parent.url || '/' || tags_category.slug
FROM "tags_category" parent
WHERE parent.id = tags_category.parent_id
)
WHERE lft > %s AND rght < %s AND level = %s
"""
count = cursor.execute(sql, [self.lft, self.rght, level])
def __unicode__(self):
return self.name
def __repr__(self):
return u'<Category: %s>' % self.name
def update_category_url(sender, instance, **kwargs):
instance.update_url()
post_save_changed.connect(update_category_url, sender=Category, fields=['slug', 'parent'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment