2015-07-10 12 views
9

ich für meine Kommentare Anwendung ein django-MPTT Paket verwende und ich habe folgendes Modell dafür:Dynamische Ordnung in django-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 

Ich möchte Benutzer die Möglichkeit geben, Kommentar Baum von Hotness zu sortieren oder Erstellungsdatum. Ist es möglich, order_insertion_by Feld von Sicht zu bearbeiten, um 2 Arten der Sortierung zu erzeugen (nach Datum, nach Schärfe)? Danke für Ihre Hilfe.

+0

Haben Sie eine Lösung darüber finden? –

+0

Nein, habe ich nicht. :( – Peterek

+0

Ich habe ein paar Tests mit meinem Codebeispiel (python3) gemacht und es scheint zu funktionieren - ABER es wäre schön, wenn jemand anderes es ausprobieren würde. – biodiv

Antwort

3

The Modified Preorder Tree Traversal (MPTT) ist ein Weg, um eine Baumstruktur mit einer Abfrage nach links (in lft MPTT) und rechten (rgt) Numerierung abzurufen wie hier http://sitepointstatic.com/graphics/sitepoint_numbering.gif gezeigt.

mehr als ein order_insertion_by definieren wird die folgende (nach mptts Kommentare) tun:

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

""" 

Wenn ich es richtig verstehe, gibt order_insertion_by die Reihenfolge der Geschwister, die Kinder (nicht Nachkommen) eines Elternteils darstellen Element. Wenn Sie zwei verschiedene Aufträge haben möchten, müssten sich auch lft und rgt ändern, und somit ist es ein zweiter Baum. Dies ist nicht in mpt enthalten.

könnten Sie tun noch

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

aber Sie würden die Baumstruktur verlieren. Es ist im Allgemeinen nicht möglich, die Baumstruktur beizubehalten und den gesamten Baum durch etwas anderes zu ordnen, z. Schärfe. Stellen Sie sich vor Sie haben die folgenden:

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

die in

Comment2 
Comment3 
Comment1 

würde es bestellt, aber Comment2 ist nicht auf Comment1 angebracht. Wenn Sie als durch order_insertion_by auf einer Geschwister-Level-Basis definiert mit etwas anderes sortieren wollen, folgendes zu erhalten:

Comment3 
Comment1 
    Comment2 

könnte man einen neuen Template-Tag wie {% recursetree objects -hotness %} schreiben kann, die über und wieder iteriert -sorts children Elemente und gibt den neuen Baum zurück. Es ist immer noch eine Datenbankabfrage - aber ich kann den Leistungseinbruch nicht schätzen.

Sie haben MPTT Gabel und mptt_tags.py bearbeiten wie folgt:

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)