2017-07-06 107 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()?