2011-08-22 54 views
2

django nonrel's documentation指出:“您必须手动编写用于合并多个查询(JOIN,select_related()等)结果的代码”。如何使用google-appengine和django-nonrel来模拟'select_related'?

有人能指向我手动添加相关数据的任何代码片段吗? @nickjohnson有一个excellent post显示如何用直接的AppEngine模型做到这一点,但我使用的是django-nonrel。

对于我特别的用途,我试图获取UserProfiles及其相关的用户模型。这应该只是两个简单的查询,然后匹配数据。

但是,使用django-nonrel,将为查询集中的每个结果启动一个新查询。我如何才能以'select_related'的方式访问相关的项目?

我试过这个,但它似乎并没有像我期望的那样工作。看看rpc统计数据,它似乎仍然在为每个显示的项目发出查询。

all_profiles = UserProfile.objects.all() 
user_pks = set() 
for profile in all_profiles: 
    user_pks.add(profile.user_id) # a way to access the pk without triggering the query 

users = User.objects.filter(pk__in=user_pks) 
for profile in all_profiles: 
    profile.user = get_matching_model(profile.user_id, users) 


def get_matching_model(key, queryset): 
    """Generator expression to get the next match for a given key""" 
    try: 
     return (model for model in queryset if model.pk == key).next() 
    except StopIteration: 
     return None 

UPDATE: 伊克...我想通了什么我的问题。

我试图提高django admin中changelist_view的效率。似乎上面的select_related逻辑在外键在我的'display_list'中时仍然会为结果集中的每一行生成额外的查询。但是,我将其归结为不同的东西。上面的逻辑不会产生多个查询(但如果你更接近模仿尼克约翰逊的方式,它会看起来更漂亮)。

问题是在ChangeList方法的第117行django.contrib.admin.views.main中有以下代码:result_list = self.query_set._clone()。所以,即使我正确地覆盖了管理员中的查询集并选择了相关的东西,这个方法也触发了一个查询集的克隆,它不保留我为我的'select related'添加的模型的属性,导致比我开始时的页面加载效率更低。

不知道该怎么办,但选择相关的东西的代码就好了。

回答

1

我不喜欢回答我自己的问题,但答案可能会帮助其他人。

这是我的解决方案,将完全基于尼克约翰逊的解决方案链接上面的查询集上的相关项目。

为了能够修改admin上的queryset以利用select相关的参数,我们必须跳过一对夫妇的箍环。这是我所做的。 'AppEngineRelatedChangeList'的'get_results'方法中唯一改变的是我删除了self.query_set._clone(),而只是使用了self.query_set。


class UserProfileAdmin(admin.ModelAdmin): 
    list_display = ('username', 'user', 'paid') 
    select_related_fields = ['user'] 

    def get_changelist(self, request, **kwargs): 
     return AppEngineRelatedChangeList 

class AppEngineRelatedChangeList(ChangeList): 

    def get_query_set(self): 
     qs = super(AppEngineRelatedChangeList, self).get_query_set() 
     related_fields = getattr(self.model_admin, 'select_related_fields', []) 
     return get_with_related(qs, *related_fields) 

    def get_results(self, request): 
     paginator = self.model_admin.get_paginator(request, self.query_set, self.list_per_page) 
     # Get the number of objects, with admin filters applied. 
     result_count = paginator.count 

     # Get the total number of objects, with no admin filters applied. 
     # Perform a slight optimization: Check to see whether any filters were 
     # given. If not, use paginator.hits to calculate the number of objects, 
     # because we've already done paginator.hits and the value is cached. 
     if not self.query_set.query.where: 
      full_result_count = result_count 
     else: 
      full_result_count = self.root_query_set.count() 

     can_show_all = result_count self.list_per_page 

     # Get the list of objects to display on this page. 
     if (self.show_all and can_show_all) or not multi_page: 
      result_list = self.query_set 
     else: 
      try: 
       result_list = paginator.page(self.page_num+1).object_list 
      except InvalidPage: 
       raise IncorrectLookupParameters 

     self.result_count = result_count 
     self.full_result_count = full_result_count 
     self.result_list = result_list 
     self.can_show_all = can_show_all 
     self.multi_page = multi_page 
     self.paginator = paginator 
相关问题