博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
django 非常实用的无限级分类功能
阅读量:2429 次
发布时间:2019-05-10

本文共 4056 字,大约阅读时间需要 13 分钟。

利用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
(
)

转载地址:http://kdsmb.baihongyu.com/

你可能感兴趣的文章
程序员掉头发的原因找到了 | 每日趣闻
查看>>
腾讯:我就是那只吃了假辣椒酱的憨憨。老干妈:企鹅你可长点心吧!
查看>>
倒计时1天 | 张钹院士领衔,AI开发者大会20大论坛全攻略!
查看>>
运维工程师的日常?? | 每日趣闻
查看>>
31 道 Java 核心面试题,统统打包给你!
查看>>
太拼了:谷歌第一编程语言小白也能学会!
查看>>
三分钟黑了阿里?马云下死命令留他?吴翰清辟谣:我没黑过阿里
查看>>
如果重新一次高考,你还会选择软件专业当程序员吗? | 每日趣闻
查看>>
如何设计一个安全可靠的 API 接口?
查看>>
一年一度程序员“补课”季来袭,618 背后技术大公开!
查看>>
我和美国 AI 博士聊了聊:2020 年,这件事比存钱更重要!
查看>>
陈芳,高考之后我要学计算机专业,将来做 IT 发财了,我就娶你!
查看>>
“编程能力差的程序员,90%输在这事上!”谷歌AI专家:都是瞎努力!
查看>>
张一鸣做电商:再造一个“抖音”
查看>>
“你写的 Bug 让我来改好吗” | 每日趣闻
查看>>
大厂技术文档:Redis+Nginx+Spring全家桶+Dubbo精选
查看>>
笑死,别再黑程序员了好吗? | 每日趣闻
查看>>
Python 爬取 13966 条运维招聘信息,这些岗位最吃香
查看>>
28 岁退休程序员自述:不是富二代,行政专业出身,非典型程序员
查看>>
那时刚毕业的我,曾参与惊心动魄 3Q 大战
查看>>