django 非常實用的無限級分類功能


利用model中的save方法,變相的實現遞歸循環,所有子分類都能在其中更新,感覺挺巧妙,之前的實現方式確實太爛了。    order的方法竟然支持1:23:2 這種方式的排序,輕松解決以前靠order_id排序的弊端。精簡了代碼。

其中一斷代碼: 利用reverse 方法反推url,與無限級的order 還能用在自動生成類別鏈接上,便捷靈活。

 

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 )
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

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的實現。

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://www.open-open.com/code/view/1453477576558


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM