问题
(Scroll down for updates.)
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.
I have 2 issues:
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.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.
My current code in 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]
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?
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]
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
.
I could increase the number of countries in random_countries
, but it doesn't ensure that they aren't repeated in the result.
I've been trying to use order_by()
, distinct()
, __contains
, __in
, Q()
, and exclude()
in various permutations but still haven't figured it out.
I'd also like to skip order_by()
if possible since I read that it takes up a lot, a lot of resources.
Let me know if I should throw in the towel and write raw sql.
回答1:
What you're looking for is the __contains lookup type. While the __in lookup type is checks that the value of a field is in a provided list or tuple(in your case it converts the string to a tuple containing the provided string), __contains checks that the string field contains the string you provide.
回答2:
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.
The one shown above matches:
- (^|.+,) - The beginning of the string or at least one character followed by a comma.
- %s - Replaced with the country name
- (,.+|$) - A comma followed by one or more characters, or the end of the string.
This will ensure the string you're looking for is not a segment of a larger string in a list of comma separated values.
来源:https://stackoverflow.com/questions/48912441/in-django-how-to-filter-a-model-using-a-list-of-values-but-each-value-can-be-us