2015-07-10 2 views
9

Я использую пакет Джанго-mptt для моего комментариев приложения и я следующая модель для этого:Динамический порядок в Джанго-mptt

class Comment(MPTTModel): 
    content = models.TextField(verbose_name='Treść') 
    author = models.ForeignKey(AUTH_USER_MODEL, verbose_name='Autor', blank=False, null=True) 
    is_deleted = models.BooleanField(verbose_name='Komentarz usunięty', default=False, 
            help_text='Zaznacz, aby usunąć komentarz') 

    ip = models.GenericIPAddressField(default=0, verbose_name='Adres IP') 

    content_type = models.ForeignKey(ContentType, verbose_name='Typ obiektu') 
    object_id = models.PositiveIntegerField(verbose_name='ID obiektu') 
    content_object = GenericForeignKey('content_type', 'object_id') 
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True) 
    hotness = models.FloatField(default=0) 

    created_at = models.DateTimeField(auto_now_add=False, verbose_name='Data dodania') 

    updated_at = models.DateTimeField(auto_now=True, verbose_name='Aktualizacja') 

    class MPTTMeta: 
     order_insertion_by = ('-hotness', '-created_at') 

    class Meta: 
     verbose_name = 'Komentarz' 
     verbose_name_plural = 'Komentarze' 

    def __unicode__(self): 
     if len(self.content) > 50: 
      return self.content[:50] + '...' 
     else: 
      return self.content 

Я хотел бы дать пользователю возможность сортировать комментарий древе жаркости или Дата создания. Возможно ли отредактировать поле order_insertion_by для просмотра двух типов сортировки (по дате, по горячности)? Спасибо за вашу помощь.

+0

ли вы найти решение о том, что? –

+0

Нет, я этого не делал. :( – Peterek

+0

Я сделал несколько тестов с моим примером кода ниже (python3), и, похоже, он работает - НО было бы неплохо, если бы кто-то попробовал его. – biodiv

ответ

3

The Modified Preorder Tree Traversal (MPTT) представляет собой способ получения древовидной структуры с одним запрос, используя левый (lft в mptt) и вправо (rgt) нумерации, как показано здесь http://sitepointstatic.com/graphics/sitepoint_numbering.gif.

Определение более одного order_insertion_by будет сделать следующее (в соответствии с mptts комментариями):

""" 
    Creates a filter which matches suitable right siblings for ``node``, 
    where insertion should maintain ordering according to the list of 
    fields in ``order_insertion_by``. 

    For example, given an ``order_insertion_by`` of 
    ``['field1', 'field2', 'field3']``, the resulting filter should 
    correspond to the following SQL:: 

     field1 > %s 
     OR (field1 = %s AND field2 > %s) 
     OR (field1 = %s AND field2 = %s AND field3 > %s) 

""" 

Если я правильно понимаю, order_insertion_by определяет порядок братьев и сестер, которые представляют собой детей (потомков) от одного из родителей элемент. Если вам нужны два разных заказа, lft и rgt должны будут также измениться, и, таким образом, это второе дерево. Это не включено в mptt.

Вы все еще могли бы сделать

Comment.objects.all().order_by('-hotness') 

но вы потеряете древовидную структуру. Как правило, невозможно поддерживать древовидную структуру и упорядочить все дерево чем-то другим, например. жаркость. Представьте, у вас есть следующие:

Comment1 (hotness 0) 
    Comment2 (hotness 2, child of Comment1) 
Comment3 (hotness 1) 

, который приведет к

Comment2 
Comment3 
Comment1 

Приказано, но Comment2 не привязан к Comment1. Если вы хотите отсортировать, используя что-то другое, чем определенное order_insertion_by на родственной-уровне-основе, чтобы получить следующее:

Comment3 
Comment1 
    Comment2 

один мог бы написать новый тег шаблона, как {% recursetree objects -hotness %}, что перебирает и вновь -sorts children элементов и возвращает новое дерево. Это все еще один запрос к базе данных, но я не могу оценить производительность.

Вам придется раскошелиться mptt и редактировать mptt_tags.py следующим образом:

class RecurseTreeNode(template.Node): 
    def __init__(self, template_nodes, queryset_var, order_var=None): 
     self.template_nodes = template_nodes 
     self.queryset_var = queryset_var 
     self.order_var = order_var 

    def _render_node(self, context, node): 
     bits = [] 
     context.push() 

     children = node.get_children() 

     if children and self.order_var is not None: 
      children = children.order_by(self.order_var)    

     for child in children: 
      bits.append(self._render_node(context, child)) 
     context['node'] = node 
     context['children'] = mark_safe(''.join(bits)) 
     rendered = self.template_nodes.render(context) 
     context.pop() 
     return rendered 

    def render(self, context): 
     queryset = self.queryset_var.resolve(context) 
     roots = cache_tree_children(queryset) 
     bits = [self._render_node(context, node) for node in roots] 
     return ''.join(bits) 


@register.tag 
def recursetree(parser, token): 
    bits = token.contents.split() 
    if len(bits) < 2: 
     raise template.TemplateSyntaxError(_('%s tag requires a queryset') % bits[0]) 

    queryset_var = template.Variable(bits[1]) 

    if len(bits) == 3: 
     order_var = bits[2] 
    else: 
     order_var = None 

    template_nodes = parser.parse(('endrecursetree',)) 
    parser.delete_first_token() 

    return RecurseTreeNode(template_nodes, queryset_var, order_var) 
Смежные вопросы