장고

2012-01-13 4 views
1

에서 가장 최근에 대여 한 동영상을 취득하는 것은 그래서 당신은 다음과 같은 두 개의 테이블이 상상 :장고

(
    SELECT movie_id, count(movie_id) AS rent_count 
    FROM movieRentals 
    WHERE dateRented > [TIME_ARG_HERE] 
    GROUP BY movie_id 
) 
UNION 
(
    SELECT id AS movie_id, 0 AS rent_count 
    FROM movie 
    WHERE movie_id NOT IN 
    (
     SELECT movie_id 
     FROM movieRentals 
     WHERE dateRented > [TIME_ARG_HERE] 
     GROUP BY movie_id 
    ) 
) 

는 (의 수를 가져옵니다 : 직접 SQL로

CREATE movies (
    id int, 
    name varchar(255), 
    ... 
    PRIMARY KEY (id) 
); 

CREATE movieRentals (
    id int, 
    movie_id int, 
    customer varchar(255), 
    dateRented datetime, 
    ... 
    PRIMARY KEY (id) 
    FOREIGN KEY (movie_id) REFERENCES movies(id) 
); 

을, 나는대로이 쿼리를 접근하는 것

: 모든 영화 대여, ID로, 이후 지정된 날짜)

분명히

이 테이블의 장고 버전은 간단한 모델입니다

그러나, 해당 쿼리에이 번역하는 것은 어려운 것으로 나타납니다 :이 방법이 작동하는 것 같다 동안

timeArg = datetime.datetime.now() - datetime.timedelta(7,0) 
queryset = models.MovieRentals.objects.all() 
queryset = queryset.filter(dateRented__gte=timeArg) 
queryset = queryset.annotate(rent_count=Count('movies')) 

querysetTwo = models.Movies.objects.all() 
querysetTwo = querysetTwo.filter(~Q(id__in=[val["movie_id"] for val in queryset.values("movie_id")])) 
# Somehow need to set the 0 count. For now force it with Extra: 
querysetTwo.extra(select={"rent_count": "SELECT 0 AS rent_count FROM app_movies LIMIT 1"}) 

# Now union these - for some reason this doesn't work: 
# return querysetOne | querysetTwo 
# so instead 
set1List = [_getMinimalDict(model) for model in queryset] 
# Where getMinimalDict just extracts the values I am interested in. 
set2List = [_getMinimalDict(model) for model in querysetTwo] 
return sorted(set1List + set2List, key=lambda x: x['rent_count']) 

그러나, 그것은 매우 느립니다. 제가 누락 된 더 좋은 방법이 있습니까?

+0

SQL 쿼리를 어떻게해야합니까? 그 날 이후 임대 된 영화뿐만 아니라 그 이후 임대되지 않은 * 영화도 대여 한 상태로 [TIME ARG HERE] 이후 대여 한 모든 영화를 반환하는 것처럼 보입니다. –

+0

죄송합니다. 본 적이 없습니다. LIMIT 1은 확실히 삭제되어야하며, 나는 내가 생각한 것을 모른다. 그렇지 않으면 올바른 것입니다. –

답변

1

이 훨씬 쉽게는 다음과 같이 표현 될 것이다 :

SELECT movie.id, count(movieRentals.id) as rent_count 
FROM movie 
LEFT JOIN movieRentals ON (movieRentals.movie_id = movie.id AND dateRented > [TIME_ARG_HERE]) 
GROUP BY movie.id 

왼쪽 [TIME_ARG_HERE] 이후 unrented 각 영화에 대해 하나의 행을 생산하지만, 그 행의 movieRentals.id 것이다 가입 열은 NULL입니다.

그런 다음 COUNT(movieRentals.id)은 존재하는 모든 대여 항목을 계산하고 NULL 값만 있으면 0을 반환합니다.

1

나는 명백한 것을 놓치고 있어야합니다. 왜 다음 일 것 (위의 코드와 같이)

또한
queryset = models.MovieRentals.filter(dateRented__gte=timeArg).values('movies').annotate(Count('movies')).aggregate(Min('movies__count')) 

, 절은 체인 될 수 있으며, 지속적으로 중간 검색어 세트에 queryset 변수를 설정하는 이유가 없도록. 바로 SQL로

+0

Min ('movies__count')를하는 것의 문제는 한 번 이상 대여 한 영화 만 남기고 있다는 것입니다. 임대하지 않은 경우는 모두 덮어 씁니다. 아웃. –