在Django中,如何使用值列表过滤模型,但每个值只能使用一次? [英] In Django, how to filter a model using a list of values but each value can be used only once?

查看:34
本文介绍了在Django中,如何使用值列表过滤模型,但每个值只能使用一次?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(向下滚动以获取更新。)

(Scroll down for updates.)

我是Django的新手。我使用的是Mezzanine 4.2.3(根据requirements.txt,使用Django 1.10.8)。我有一个有关电影的详细信息的Postgres数据库。我想在一个页面上显示10部电影。

I'm new to Django. I'm using Mezzanine 4.2.3 (Django 1.10.8 under the hood according to requirements.txt). I have a Postgres database of details about movies. I want to display 10 movies on a page.

我有2个问题:


  1. 每部电影都必须来自其他国家/地区。到目前为止,我只能从较大的列表中获得10个随机国家/地区的列表。我不知道如何使用 .objects.filter()来确保没有重复的国家。

  1. Each movie must be from a different country. So far, I can only get a list of 10 random countries from a larger list. I don't know how to use .objects.filter() in a way that makes sure there are no repeated countries.

某些电影是由多个国家/地区制作的,并作为字符串包含在数据库中,例如'塔吉克斯坦,巴布亚新几内亚,韩国'。但是 .objects.filter()函数仅返回其中包含单个国家/地区的电影。

Some movies are produced by more than one country, and they are contained as strings in the database, for instance 'Tajikistan,Papua New Guinea,Korea'. But the .objects.filter() function only returns movies with a single country in it.

我当前在 views.py 中的代码:

from .countries import countries # this is a Python list of countries

class MoviesListView(generic.ListView):
    model = Movies

    def get_queryset(self):
        random_countries = []

        i = 0
        while i < 10:
            country_choice = random.choice(countries)
            if country_choice in random_countries:
                pass
            else:
                random_countries.append(country_choice)
            i += 1

        return Movies.objects.filter(production_countries__in=random_countries)[:10]

我已经四处搜寻并查看了Django文档,但未能找到解决方案。最好的方法是什么?我必须使用psycopg2连接到数据库,使用sql来获取10个符合我的条件的电影,然后从那里创建上下文,还是Django已经为此提供了一些东西?

I've googled around and looked into the Django documentation but haven't been able to find solutions. What's the best way to do this? Must I connect to the database with psycopg2, use sql to get 10 movies that fit my criteria and then create a context from there, or does Django already have something for this?

更新2018年2月21日,晚上10:30 :部分感谢@MVanOrder(使我进入了解决方案等),最接近的解决方案是:

Update 21 Feb 2018, 10.30pm: Thanks in part to @MVanOrder (which led me to this solution, amongst others), The closest I've come to a solution is:

from django.db.models import Q
from .countries import countries # this is a Python list of countries

class MoviesListView(generic.ListView):
    model = Movies

    def get_queryset(self):
        random_countries = []

        i = 0
        while i < 10:
            country_choice = random.choice(countries)
            if country_choice in random_countries:
                pass
            else:
                random_countries.append(country_choice)
            i += 1

q = Q()
for country in random_countries:
    q |= Q(production_countries__icontains = country)

return Movies.objects.filter(q).distinct('production_countries')[:10]

这可以确保我获得10部电影,但是它们的生产国是独特的,因为它们是不同国家的不同串联,但是它们仍然在 random_countries 中重复国家。

This ensures that I get 10 movies, but their production countries are unique in that they are different concatenations of different countries, but they still repeat countries in random_countries.

我可以增加 random_countries 中的国家/地区数量,但这不能确保结果中不会重复出现这些国家。

I could increase the number of countries in random_countries, but it doesn't ensure that they aren't repeated in the result.

我一直在尝试使用 order_by() distinct() __包含 __ in Q() exclude()各种排列方式,但仍未弄清楚。

I've been trying to use order_by(), distinct(), __contains, __in, Q(), and exclude() in various permutations but still haven't figured it out.

我想尽可能跳过 order_by(),因为我读到它会占用很多资源。

I'd also like to skip order_by() if possible since I read that it takes up a lot, a lot of resources.

让我知道是否应该投入使用并编写原始sql。

Let me know if I should throw in the towel and write raw sql.

推荐答案

这是一个更好的解决方案:

Here's a better solution:

from django.db.models import Q
from .countries import countries # this is a Python list of countries

class MoviesListView(generic.ListView):
    model = Movies

    def get_queryset(self):
        random_countries = []

        i = 0
        while i < 10:
            country_choice = random.choice(countries)
            if country_choice in random_countries:
                pass
            else:
                random_countries.append(country_choice)
            i += 1

        q = Q()
        for country in random_countries:
            q |= Q(production_countries__iregex = r'(^|.+,)%s(,.+|$)' % country)

        return Movies.objects.filter(q).distinct('production_countries')[:10]

您可以使用正则表达式,而不是使用包含在搜索国家/地区中查找包含一系列字符的字符串的包含项。

Rather than using a contains that is looking for a string that contains the series of characters in the searched country, you can use a regex.

上面显示的一个匹配:


  • (^ |。+,)-字符串的开头或至少一个字符

  • %s-替换为国家名

  • (,。+ | $)-逗号后跟一个或多个字符或字符串的结尾。

这将确保您要查找的字符串不是逗号分隔值列表中较大字符串的一部分。

This will ensure the string you're looking for is not a segment of a larger string in a list of comma separated values.

这篇关于在Django中,如何使用值列表过滤模型,但每个值只能使用一次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆