django 非常实用的无限级分类功能,django非常实用,利用model中的sav


利用model中的save方法,变相的实现递归循环,所有子分类都能在其中更新,感觉挺巧妙,之前的实现方式确实太烂了。 order的方法竟然支持1:23:2 这种方式的排序,轻松解决以前靠order_id排序的弊端。精简了代码。

其中一断代码: 利用reverse 方法反推url,与无限级的order 还能用在自动生成类别链接上,便捷灵活。

1234567 def htmlpath(self): paths = [] for p in self.path.split(':'): c = ArticleCategory.objects.get(id__exact=p) url = reverse('cms.article.list', kwargs={'cid':c.id}) paths.append('<a href="%s" target="_blank">%s</a>' % (url, c.name)) return " > ".join(paths)

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051from django.db.models.signals import pre_saveclass ArticleCategory(models.Model): name = models.CharField(max_length=50) parent = models.ForeignKey('self', null=True, blank=True, related_name='children') path = models.CharField(max_length=255, null=True, blank=True) def unicode(self): if self.id == self.path: return self.name else: return self.node def _node(self): indent_num = len(self.path.split(':')) -1 indent = '....' * indent_num node = u'%s%s' % (indent, self.name) return node node = property(_node) class Meta: ordering = ['path'] #设置在model中的用途是,是在所有节点保存时递归的循环下去,更新所有的节点的路径 def save(self, * args, kwargs): super(ArticleCategory,self).save(*args, kwargs) if self.parent: self.path = '%s:%s' % (self.parent.path, self.id) else: self.path = self.id childrens = self.children.all() if len(childrens) > 0: for children in childrens: children.path = '%s:%s' % (self.path, children.id) children.save() super(ArticleCategory,self).save(args, kwargs)#信号触发,更新def inital_articlecategory_path(sender, instance,
kwargs): if instance.id: if instance.parent: instance.path = '%s:%s' % (instance.parent.path, instance.id) else: instance.path = instance.idpre_save.connect(inital_articlecategory_path, sender=ArticleCategory) admin.py 123456789101112131415161718192021class ArticleCategoryAdmin(admin.ModelAdmin): list_display = ['treenode','patha','id', ] ordering = ['path'] def patha(self, obj): if obj.parent: return u'%s > %s' % (obj.parent, obj.name) return obj.name patha.short_description = 'path' patha.allow_tags = True def treenode(self, obj): indent_num = len(obj.path.split(':')) -1 p = '<div style="text-indent:%spx;">%s</div>' % (indent_num
25, obj.name) return p treenode.short_description = 'tree path' treenode.allow_tags = Trueadmin.site.register(ArticleCategory, ArticleCategoryAdmin) 分析代码后,发现该方法可以不使用signals 来实现,在path变换后 再次运行 super(ArticleCategory,self).save(args, * kwargs) ,这样在children中才能在新的循环save中更新path时变更正确,否则path保存时会异常。

这个是不使用signals的代码,依靠model的save的实现。 1234567891011121314151617181920212223242526272829303132333435363738394041424344class ArticleCategory(models.Model): name = models.CharField(max_length=50) parent = models.ForeignKey('self', null=True, blank=True, related_name='children') path = models.CharField(max_length=255, null=True, blank=True) def unicode(self): if self.id == self.path: return self.name else: return self.node def _node(self): indent_num = len(self.path.split(':')) -1 indent = '....' * indent_num node = u'%s%s' % (indent, self.name) return node node = property(_node) class Meta: ordering = ['path'] #设置在model中的用途是,是在所有节点保存时递归的循环下去,更新所有的节点的路径 def save(self, * args, kwargs): #先保存数据,如果是新添加的数据,放在第一行是用来获得id,因为id是path的重要组成 super(ArticleCategory,self).save(*args, kwargs) if self.parent: self.path = '%s:%s' % (self.parent.path, self.id) else: self.path = self.id #更新完当前节点path后,要进行一次保存,否则在编辑类别时,子分类循环保存父类path不是最新的 super(ArticleCategory,self).save(args, * kwargs) childrens = self.children.all() if len(childrens) > 0: for children in childrens: children.path = '%s:%s' % (self.path, children.id) children.save()

评论关闭