2017-09-15 3 views
2

에어 비앤비에서 앱처럼 작동합니다. 나는 Flat 모델과 Price 모델을 가지고 있으며, 가격에는 고객이 유연한 가격대를 만들 수있는 우선 순위의 다른 유형이 있습니다.외부 쿼리를 기반으로 하위 쿼리에서 조건을 만드는 방법은 무엇입니까?

하나의 복잡한 쿼리가 붙어 있습니다. 이 쿼리는 Flats를 날짜 범위로 반환하고이 범위의 가격을 계산해야합니다. 여기


내 모델의 부분 :

class Flat(models.Model): 
    prices = models.ManyToManyField(
     'Price' 
     related_name='flats' 
    ) 
    price = models.PositiveIntegerField() 
    ... 

class Price(models.Model): 
    PRIORITY_CHOICES = ((i, i) for i in range(1, 6)) 

    priority = PositiveIntegerField(choices=PRIORITY_CHOICES) 
    start_date = models.DateField() 
    end_date = models.DateField() 
    price = models.PositiveIntegerField() 

은 지금까지 나는 매일에 의해 더 높은 우선 순위로 가격을 주석하는 방법을 알아낼. 그래서 평면가 자신의 price 필드가의 Flat에서

일부 날짜가 가격 블록없이 할 수 있습니다 : 여기


class FlatManager(models.Manager): 

    def with_prices(self, start, end): 
     days = get_days(start, end) # utils function return list of days 
     prices = {} 
     for day in days: 
      prices[str(day)] = models.Subquery(
      Price.objects.filter(
       flats=models.OuterRef('pk')). 
       filter(start_date__lte=day, end_date__gte=day). 
       order_by('-priority'). 
       values('price')[:1] 
     ) 
     return self.annotate(**price_dict) 
내 문제
입니다 : 내가 평면에 대한 사용자 지정 관리자를 썼다 고객이 유연한 가격을 사용하지 않을 경우. 내 쿼리에 조건 연산자를 추가해야하는 위치를 모르겠습니다. Price 하위 쿼리에 추가하면 중첩 때문에 Outref('price')을 사용할 수 없습니다. 해결할 때 집계 된 값의 합계를 계산하는 것이 그리 복잡하지는 않을 것이라고 생각합니다.

적어도 힌트를 줘주세요, 정말 그걸로 붙어 있습니다.

답변

0

주 쿼리로 조건을 이동하고 하위 쿼리가 None을 반환하는지 확인한 다음 Flat 모델 필드를 사용합니다. 그것은 다음과 같이 것 하나 개 date
:

day = # some date 
price = Price.objects.filter(
      flats=models.OuterRef('pk')). 
      filter(start_date__lte=day, end_date__gte=day). 
      order_by('-priority'). 
      values('price')[:1]) 
Flat.objects.annotate(price_block=Subquery(price).annotate(
    derived_price = Case(
         When(price_block__isnull=True, then='price'), 
         default=F('price_block') 
    )) 

는 그래서 derived_price 값이 Price 모델 또는 Flat 모델 price 값에서 price 값을 포함 할 경우 하위 쿼리 반환 None
하지만 내 경우에는 내가있다 날짜의 범위, 그래서 각 날짜에 대한 하위 쿼리 및 조건이 필요합니다. 또한 모든 주석이 달린 가격의 합이 필요합니다.
다음은 내가 한 일입니다.

class FlatManager(models.Manager): 

    def _construct_conditions(self, keys): 
     # Function construct conditions 
     # like in previous example for each date in range 
     annotations = {} 
     for key in keys: 
      condition = {'{}__isnull'.format(key): True, 'then': 'price'} 
      annotations['derived_{}'.format(key)] = Case(When(**condition), default=F(key)) 
     return annotations 

    def _add_prices(self, keys): 
     values = [F('derived_{}'.format(key)) for key in keys] 
     return sum(values) 

    def with_prices(self, start, end): 
     days = get_days(start, end) # utils function return list of days 
     prices = {} 
     for num, day in enumerate(days): 
      prices['price_{}'.format(num)] = Subquery(
       Price.objects.filter(
       flats=OuterRef('pk')). 
       filter(start_date__lte=day, end_date__gte=day). 
       order_by('-priority'). 
       values('weekend_price' if day.weekday() in [4, 5] else 'price')[:1] 
       # also add a condition for weekend price 
     ) 
     return (self.annotate(**prices). 
       annotate(**self._construct_conditions(prices.keys())). 
       annotate(sum=self._add_prices(prices.keys())) 
       )