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 ( ) |
本文由用戶 henghengdh 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!