django 非常实用的无限级分类功能

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

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

 

1
2
3
4
5
6
7
     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 )

 

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
42
43
44
45
46
47
48
49
50
51
from django. db. models. signals  import pre_save

class 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. id
pre_save. connect (inital_articlecategory_path , sender =ArticleCategory )

admin.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class 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  =  True
admin. site. register (ArticleCategory , ArticleCategoryAdmin )

分析代码后,发现该方法可以不使用signals 来实现,在path变换后 再次运行 super(ArticleCategory,self).save(*args, ** kwargs) ,这样在children中才能在新的循环save中更新path时变更正确,否则path保存时会异常。

这个是不使用signals的代码,依靠model的save的实现。

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
42
43
44
class 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 ( )
主题推荐
django 递归 unicode 数据 instance
猜你在找
无限级分类非递归算法存储过程版GUID主键完整数据库示例_2插入记录
非递归的无限级分类目录
递归实现无限级栏目的分类
无限级分类非递归算法存储过程版GUID主键完整数据库示例_1表结构
无限级分类非递归算法存储过程版GUID主键完整数据库示例_4显示记录
ASPNET无限级分类的非递归实现存储过程版
DropDownList 无限级分类 树状显示 递归
无限级分类非递归算法存储过程版GUID主键完整数据库示例_4显示记录
递归处理List集合无限级分类
无限级分类非递归算法存储过程版GUID主键完整数据库示例_3删除记录
id="ad_frm_0" frameborder="0" scrolling="no" src="http://blog.csdn.net/common/ad.html?t=4&containerId=ad_cen&frmId=ad_frm_0" style="border-width: 0px; overflow: hidden; width: 746px; height: 90px;">
查看评论

  暂无评论

* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
id="ad_frm_1" frameborder="0" scrolling="no" src="http://blog.csdn.net/common/ad.html?t=5&containerId=ad_bot&frmId=ad_frm_1" style="border-width: 0px; overflow: hidden; width: 746px; height: 0px;">
  • 个人资料
  •  
    • 访问:249293次
    • 积分:3731
    • 等级: 
    • 排名:第3335名
    • 原创:120篇
    • 转载:86篇
    • 译文:0篇
    • 评论:41条
  • 文章存档
  • 推荐文章
  • id="ad_frm_2" frameborder="0" scrolling="no" src="http://blog.csdn.net/common/ad.html?t=12&containerId=ad_commend&frmId=ad_frm_2" style="border-width: 0px; overflow: hidden; width: 182px; height: 200px;">
  • 最新评论
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值