2

django nonrel의 documentation에는 "여러 쿼리 (JOIN, select_related() 등)의 결과를 병합하기위한 코드를 수동으로 작성해야합니다."Google App Engine 및 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 : 출몰하고 ... 나는 내 문제가 무엇인지 알아 냈어.

장고 관리자의 changelist_view의 효율성을 높이려고했습니다. 외래 키가 'display_list'에있을 때 위의 select_related 논리가 여전히 결과 집합의 각 행에 대한 추가 쿼리를 생성하고있는 것처럼 보였습니다. 그러나, 나는 그것을 다른 무엇인가로 추적했다. 위의 논리는 여러 쿼리를 생성하지 않습니다 (하지만 Nick Johnson의 방식을 더 자세히 모방하면 훨씬 더 돋보입니다).

문제점은 ChangeList 메소드의 117 줄에있는 django.contrib.admin.views.main에 다음 코드가 있다는 것입니다. result_list = self.query_set._clone(). 따라서 관리자의 쿼리 세트를 적절하게 재정의하고 관련 항목을 선택 했더라도이 방법은 쿼리 세트의 복제를 트리거하여 내 '관련 항목 선택'을 위해 추가 한 모델의 특성을 유지하지 않습니다. 시작했을 때보 다 비효율적 인 페이지로드가 발생했습니다.

아직 무엇을해야할지 모르지만 관련 항목을 선택하는 코드는 괜찮습니다.

답변

1

나는 내 자신의 질문에 답하는 것을 좋아하지 않지만, 그 답은 다른 사람들에게 도움이 될 수 있습니다.

위 링크 된 닉 존슨의 솔루션을 기반으로하는 쿼리 세트에서 관련 항목을 얻을 수있는 해결책은 다음과 같습니다.

관리자의 쿼리 세트를 수정하여 선택 관련을 사용하려면 몇 개의 농구를 뛰어 넘어야합니다. 여기 내가 한 일이 있습니다. '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