2017-07-06 144 views
0

的Django查詢我有以下型號:複雜的過濾器

... 
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') 
    ... 

在應用中,一個User可以產生VoteAnnotation實例。 A User只能爲Annotation實例投票。 我想獲得一個TaxonomyNode設置的查詢,User仍然可以註釋它的至少一個Annotation。現在,我這樣做的:

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

我想有一個辦法做到這一點在一個查詢,這將加快這一進程相當多。簡而言之,我想從TaxonomyNode集合中排除,其所有全部的註釋已經由用戶投票過一次。

任何想法,我怎麼能做到這一點?用Django的ORM或SQL? 我有Django的版本1.10.6

回答

0

嘗試使用此:

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

有將只有一個爲select_related將返回相關taxonomy_node在單個查詢SQL查詢。也可能有更好的方法來刪除重複,例如:通過使用.distinct()

+0

很好! 刪除重複這種方式需要一段時間(我有近700k註釋) – XavierFav

+0

你可以試試這個:set([a.taxonomy_node for a unvoted_annotations]) –

0

我迄今所做的:

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) 

我做兩個查詢,但第二個是不是非常昂貴。 它比我的原始版本更快。 但我做的並不是真正的美麗。沒有辦法直接從Annotation集合中獲取TaxonomyNode的查詢集合?然後在其中應用Disctinct()?