2017-07-06 5 views
0

Ich habe folgendes Modell:Django Anfragen mit komplexen Filter

... 
from django.contrib.auth.models import User 


class TaxonomyNode(models.Model): 
    node_id = models.CharField(max_length=20) 
    name = models.CharField(max_length=100) 
    ... 


class Annotation(models.Model): 
    ... 
    taxonomy_node = models.ForeignKey(TaxonomyNode, blank=True, null=True) 


class Vote(models.Model): 
    created_by = models.ForeignKey(User, related_name='votes', null=True, on_delete=models.SET_NULL) 
    vote = models.FloatField() 
    annotation = models.ForeignKey(Annotation, related_name='votes') 
    ... 

In der App, eine UserVote für eine Annotation Instanz erzeugen kann. Ein Userkann nur einmal für eine Annotation Instanz abstimmen. Ich möchte eine Abfrage mit der TaxonomyNode, die eine User kann immer noch kommentieren mindestens eine seiner Annotation. Vorerst tue es mich so:

def user_can_annotate(node_id, user): 
    if Annotation.objects.filter(node_id=node_id).exclude(votes__created_by=user).count() == 0: 
     return False 
    else: 
     return True 

def get_categories_to_validate(user): 
    """ 
    Returns a query set with the TaxonomyNode which have Annotation that can be validated by a user 
    """ 
    nodes = TaxonomyNode.objects.all() 
    nodes_to_keep = [node.node_id for node in nodes if self.user_can_annotate(node.node_id, user)] 
    return nodes.filter(node_id__in=nodes_to_keep) 


categories_to_validate = get_category_to_validate(<user instance>) 

Ich denke, es eine Möglichkeit, es in einer Abfrage zu tun, ist, dass der Prozess sehr viel beschleunigen würde. Kurz gesagt, ich möchte aus dem TaxonomyNode Set, alle Knoten, die ihre Annotationen schon einmal vom Benutzer gewählt haben, ausschließen.

Irgendeine Idee, wie ich es tun könnte? Mit Django ORM oder in SQL? Ich habe Django Version 1.10.6

Antwort

0

Versuchen Sie, diese zu nutzen:

#SQL query 
unvoted_annotations = Annotation.objects.exclude(votes__created_by=user).select_related('taxonomy_node') 

#remove duplicates 
taxonomy_nodes=[] 
for annotation in unvoted_annotations: 
    if annotation.taxonomy_node not in taxonomy_nodes: 
     taxonomy_nodes.append(annotation.taxonomy_node) 

Es würde nur eine SQL-Abfrage, wie select_related wird die zugehörige taxonomy_node in einer einzigen Abfrage zurück. Auch könnte es eine bessere Möglichkeit geben, Duplikate zu entfernen, zB: .distinct().

+0

Das ist schön! Entfernen von Duplikaten auf diese Weise dauert eine Weile (ich habe fast 700k Annotationen) – XavierFav

+0

Sie können dies versuchen: set ([a.taxonomy_node für eine in unvoted_annotations]) –

0

Was ich bisher getan haben:

taxonomy_node_pk = [a[0] for a in Annotation.objects.exclude(votes__created_by=user) 
    .select_related('taxonomy_node').values_list('taxonomy_node').distinct()] 

nodes = TaxonomyNode.objects.filter(pk__in=taxonomy_node_pk) 

Ich mache zwei Abfragen, aber die zweite ist nicht sehr teuer. Es ist ziemlich schneller als meine ursprüngliche Version. Noch was ich tue ist nicht wirklich beatifull. Es gibt keine Möglichkeit, einen Abfragesatz von TaxonomyNode direkt aus dem Annotation-Set zu erhalten. Und dann indectinct() anwenden?