Site Sections: Satchmo Main | Wiki | Demo Store |

Ticket #202: product-models-mptt-r3.diff

File product-models-mptt-r3.diff, 6.0 kB (added by hkpark, 1 year ago)

r3 11/02/07 05:09:25 changes

  • models.py

    old new  
    1111from decimal import Decimal 
    1212from django.conf import settings 
    1313from django.core import validators, urlresolvers 
    14 from django.db import models 
     14from django.db import models, connection, transaction 
    1515from django.utils.translation import ugettext_lazy as _ 
    1616from satchmo.configuration import config_value 
    1717from satchmo.shop.utils import url_join 
     
    3838    name = models.CharField(_("Name"), core=True, max_length=200) 
    3939    slug = models.SlugField(prepopulate_from=('name',), 
    4040        help_text=_("Used for URLs")) 
    41     parent = models.ForeignKey('self', blank=True, null=True, 
    42         related_name='child') 
     41    parent = models.ForeignKey('self', blank=True, null=True, related_name='child') 
    4342    meta = models.TextField(_("Meta Description"), blank=True, null=True, 
    4443        help_text=_("Meta description for this category")) 
    4544    description = models.TextField(_("Description"), blank=True, 
    4645        help_text="Optional") 
    47  
     46     
     47    # category of which tree since we can have multiple root categories 
     48    tree_id = models.PositiveIntegerField(db_index=True) 
     49     
     50    #Left and Right are keywords in SQL so we purposely misspell them 
     51    lft = models.PositiveIntegerField(db_index=True) 
     52    rght = models.PositiveIntegerField(db_index=True) 
     53     
    4854    def _recurse_for_parents(self, cat_obj): 
    4955        p_list = [] 
    50         if cat_obj.parent_id: 
    51             p = cat_obj.parent 
    52             p_list.append(p) 
    53             if p != self: 
    54                 more = self._recurse_for_parents(p) 
    55                 p_list.extend(more) 
    56         if cat_obj == self and p_list: 
    57             p_list.reverse() 
     56        if cat_obj.parent: 
     57            try: 
     58                #removes the recursion and gets the parents in one query 
     59                p_list = Category.objects.filter(lft__lt=cat_obj.lft, rght__gt=cat_obj.rght, tree_id=cat_obj.tree_id).order_by('lft') 
     60            except IndexError: 
     61                pass 
    5862        return p_list 
    5963 
     64    #def _set_parent(self, parent): 
     65    #    # if parent is set, get or create the parent node 
     66    #    self.parent, created = Category.objects.get_or_create( 
     67    #                name=parent.name, slug=parent.slug, description=parent.description, 
     68    #                defaults={'tree_id': self.next_tree_id, 'lft': 1, 'rght': 2}) 
     69    # 
     70    #def _get_parent(self): 
     71    #    return self.parent_category 
     72    # 
     73    #parent = property(_get_parent, _set_parent) 
     74    
    6075    def get_absolute_url(self): 
    6176        parents = self._recurse_for_parents(self) 
    6277        slug_list = [cat.slug for cat in parents] 
     
    87102        name_list.append(self.name) 
    88103        return self.get_separator().join(name_list) 
    89104 
     105    def _get_next_tree_id(self): 
     106        sql = 'select max(tree_id) from %s' % self._meta.db_table 
     107        cursor = connection.cursor() 
     108        cursor.execute(sql) 
     109        row = cursor.fetchone() 
     110        return row[0] and (row[0] + 1) or 1 
     111 
     112    #multi-root categories, need a unique tree id for the categories 
     113    next_tree_id = property(_get_next_tree_id) 
     114     
     115    @transaction.commit_on_success 
    90116    def save(self): 
    91         parents = self._recurse_for_parents(self) 
    92         if self in parents: 
    93             raise validators.ValidationError(_("You must not save a category in itself!")) 
     117        #parents = self._recurse_for_parents(self) 
     118        #if self in parents: 
     119        #   raise validators.ValidationError(_("You must not save a category in itself!")) 
     120        # If parent category is set, we need to update the whole tree to the right of it. 
     121        if self.parent: 
     122            
     123            cursor = connection.cursor() 
     124             
     125            #Left and Right are keywords in SQL so we purposely misspell them 
     126            #and keep misspellings in variable names intently 
     127            target_rght = self.parent.rght - 1 
     128 
     129            cursor.execute("UPDATE `%s` " \ 
     130                           "SET `rght` = `rght` + 2 " \ 
     131                           "WHERE tree_id = '%i' " 
     132                           "AND `rght` > %i" % (self._meta.db_table, self.parent.tree_id, int(target_rght))) 
     133 
     134            cursor.execute("UPDATE `%s` " \ 
     135                           "SET `lft` = `lft` + 2 " \ 
     136                           "WHERE tree_id = '%i' " 
     137                           "AND `lft` > %i" % (self._meta.db_table, self.parent.tree_id, int(target_rght))) 
     138             
     139            self.tree_id = self.parent.tree_id 
     140            self.lft = target_rght + 1 
     141            self.rght = target_rght + 2 
     142        else: 
     143            # can't find a parent so set it as a root category 
     144            self.tree_id = self.next_tree_id 
     145            self.lft = 1 
     146            self.rght = 2 
     147 
    94148        super(Category, self).save() 
    95149 
    96150    def _flatten(self, L): 
     
    103157 
    104158    def _recurse_for_children(self, node): 
    105159        children = [] 
    106         children.append(node) 
    107         for child in node.child.all(): 
    108             if child != self: 
    109                 children_list = self._recurse_for_children(child) 
    110                 children.append(children_list) 
     160        if node: 
     161            try: 
     162                #removes the recursion and gets the children in one query 
     163                children = Category.objects.filter(lft__gt=node.lft, rght__lt=node.rght, tree_id=node.tree_id).order_by('lft') 
     164            except IndexError: 
     165                pass 
    111166        return children 
    112167 
    113168    def get_all_children(self): 
     
    115170        Gets a list of all of the children categories. 
    116171        """ 
    117172        children_list = self._recurse_for_children(self) 
    118         flat_list = self._flatten(children_list[1:]) 
    119         return flat_list 
     173        return self._flatten(children_list[0:1]) 
    120174 
    121175    class Admin: 
    122176        list_display = ('name', '_parents_repr') 
    123         ordering = ['parent', 'name'] 
     177        ordering = ['tree_id', 'lft', 'name'] 
    124178 
    125179    class Meta: 
    126         ordering = ['parent', 'name'] 
     180        ordering = ['tree_id', 'lft', 'name'] 
    127181        verbose_name = _("Category") 
    128182        verbose_name_plural = _("Categories") 
    129183