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

2016-01-23 0 349
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
(
)

遇见资源网 python django 非常实用的无限级分类功能 http://www.ox520.com/16056.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务