2015-07-10 7 views
9

Sto usando un pacchetto django-MPTT per la mia applicazione commenti e ho seguito il modello per questo:ordine dinamica 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 

vorrei dare la possibilità all'utente di ordinare commento albero dal calore o data di creazione. È possibile modificare il campo order_insertion_by dalla vista per generare 2 tipi di ordinamento (per data, per piccantezza)? Grazie per l'aiuto.

+0

Hai trovato una soluzione a tale proposito? –

+0

No, non l'ho fatto. :( – Peterek

+0

Ho fatto alcuni test con il mio esempio di codice qui sotto (python3) e sembra funzionare, ma sarebbe bello se qualcuno lo provasse. – biodiv

risposta

3

Il Modified Preorder Tree Traversal (MPTT) è un modo per recuperare una struttura ad albero con una sola query utilizzando a sinistra (lft in MPTT) e destra (rgt) numerazione, come mostrato qui http://sitepointstatic.com/graphics/sitepoint_numbering.gif.

Definire più di un order_insertion_by farà quanto segue (secondo mptts commenti):

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

""" 

Se ho ben capito, order_insertion_by specifica l'ordine dei fratelli, che rappresentano i bambini (non discendenti) di un genitore elemento. Se vuoi due ordini diversi, lo lft e lo rgt dovrebbero cambiare, e quindi è un secondo albero. Questo non è incluso in mptt.

Si potrebbe ancora fare

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

ma si perderebbe la struttura ad albero. Generalmente non è possibile mantenere la struttura ad albero e ordinare l'intero albero con qualcos'altro, ad es. piccantezza. Immaginate di avere la seguente:

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

che si tradurrebbe in

Comment2 
Comment3 
Comment1 

Si è ordinato, ma Comment2 non è attaccato al Comment1. Se si desidera ordinare utilizzando qualcosa di diverso definito da order_insertion_by su un fratello di livello-base, per ottenere i seguenti:

Comment3 
Comment1 
    Comment2 

si potrebbe essere in grado di scrivere un nuovo tag modello come {% recursetree objects -hotness %} che scorre sopra e ri -sorts children elementi e restituisce il nuovo albero. È ancora una query di database - ma non riesco a stimare l'impatto sulle prestazioni.

Si dovrà sborsare MPTT e modificare mptt_tags.py come segue:

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)