利用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 ( ) |
-
猜你在找
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;">
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;">
核心技术类目
全部主题
Hadoop
AWS
移动游戏
Java
Android
iOS
Swift
智能硬件
Docker
OpenStack
VPN
Spark
ERP
IE10
Eclipse
CRM
JavaScript
数据库
Ubuntu
NFC
WAP
jQuery
BI
HTML5
Spring
Apache
.NET
API
HTML
SDK
IIS
Fedora
XML
LBS
Unity
Splashtop
UML
components
Windows Mobile
Rails
QEMU
KDE
Cassandra
CloudStack
FTC
coremail
OPhone
CouchBase
云计算
iOS6
Rackspace
Web App
SpringSide
Maemo
Compuware
大数据
aptech
Perl
Tornado
Ruby
Hibernate
ThinkPHP
HBase
Pure
Solr
Angular
Cloud Foundry
Redis
Scala
Django
Bootstrap
- 个人资料
-
- 访问:249293次
- 积分:3731
- 等级:
- 排名:第3335名
- 原创:120篇
- 转载:86篇
- 译文:0篇
- 评论:41条
- 文章搜索
- 文章分类
- 阅读排行
- (20708)
- (11260)
- (8675)
- (7812)
- (7777)
- (6932)
- (5285)
- (5090)
- (4350)
- (4031)
- 评论排行
- (5)
- (5)
- (4)
- (4)
- (3)
- (3)
- (2)
- (2)
- (2)
- (2)
- 推荐文章
- 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;">
- 最新评论
: 非常感谢分享。
: 明文超长怎么解决的?
: @u013074873:正是因为没有所以需要添加这个配置才能生效
: 开启用户的验证码是在Customer Configuration 里面的captcha里面........
: @wj196:明文过长? 方便发下明文的内容吗?
: 您好,您上面提供的实例,我们可以使用,但是遇到加
暂无评论