Python 在Django获得最近租用最少的电影
因此,假设您有以下两个表:Python 在Django获得最近租用最少的电影,python,sql,django,Python,Sql,Django,因此,假设您有以下两个表: 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 (mo
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)
);
直接使用SQL,我将按照以下方式处理此查询:
(
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
)
)
(按id获取自给定日期以来所有电影租赁的计数)
显然,这些表的Django版本是简单的模型:
class Movies(models.Model):
name = models.CharField(max_length=255, unique=True)
class MovieRentals(models.Model):
customer = models.CharField(max_length=255)
dateRented = models.DateTimeField()
movie = models.ForeignKey(Movies)
但是,将其转换为等效查询似乎很困难:
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'])
然而,尽管这种方法似乎有效,但速度却令人难以置信。有没有更好的方法让我错过了呢?我肯定错过了一些显而易见的东西。为什么以下方法不起作用:
queryset = models.MovieRentals.filter(dateRented__gte=timeArg).values('movies').annotate(Count('movies')).aggregate(Min('movies__count'))
此外,子句可以链接(如上面的代码所示),因此没有理由不断地将
queryset
变量设置为中间queryset。使用直接SQL,这将更容易表示为:
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]以来未转发的每部电影生成一行,但在这些行中,movieRentals.id列将为NULL
然后,
COUNT(movieRentals.id)
将对存在的所有租金进行计数,如果只有空值,则返回0。SQL查询应该做什么?在我看来,它返回了[TIME ARG HERE]之后租的所有电影,以及自该日期起的租金计数,以及一部自该日期起就没有被租过的电影。抱歉,从未看过这部电影。限制1肯定应该取消,我不知道我在想什么。否则,这是正确的。只做一个Min(‘电影计数’)的问题是它只会让我们租一次或多次电影——任何没有租的都会被过滤掉。出来