我试图建立一个搜索页面,允许用户找到符合某些阈值标准的模型的任何实例,并且我在避免严重冗余代码方面遇到麻烦。我希望有更好的办法。下面是一个略显做作的示例,可以说明我要做的事情,并在最后对相关代码进行了调整。用户将通过复选框与搜索进行交互。
models.py:
class Icecream(models.Model()):
name = models.CharField()
bad_threshold = models.IntegerField()
okay_threshold = models.IntegerField()
tasty_threshold = models.IntegerField()
delicious_threshold = models.IntegerField()
views.py:
def search_icecreams(request):
user = request.user
q_search = None
if 'taste_search' in request.GET:
q_search = taste_threshold_set(request, user, q_search)
if q_search == None:
icecream_list = Icecream.objects.order_by('name')
else:
icecream_list = College.objects.filter(q_search)
context = { 'icecream_list' : icecream_list }
return render(request, '/icecream/icecreamsearch.html', context)
我想要删减的相关代码如下,这几乎是直接来自我的项目,只是更改了名称。
def taste_threshold_set(request, user, q_search):
threshold = request.GET.getlist('taste_search')
user_type_tolerance = user.profile.get_tolerance_of(icea
# 1-5 are the various thresholds. They are abbreviated to cut down on the
# length of the url.
if '1' in threshold:
new_q = Q(bad_threshold__gt = user.profile.taste_tolerance)
if q_search == None:
q_search = new_q
else:
q_search = (q_search) | (new_q)
if '2' in threshold:
new_q = Q(bad_threshold__lte=user.profile.taste_tolerance) &
~Q(okay_threshold__lte=user.profile.taste_tolerance)
if q_search == None:
q_search = new_q
else:
q_search = (q_search) | (new_q)
if '3' in threshold:
new_q = Q(okay_threshold_3__lte=user.profile.taste_tolerance) &
~Q(tasty_threshold__lte=user.profile.taste_tolerance)
if q_search == None:
q_search = new_q
else:
q_search = (q_search) | (new_q)
if '4' in threshold:
new_q = Q(tasty_threshold__lte=user.profile.taste_tolerance) &
~Q(delicious_threshold__lte=user.profile.taste_tolerance)
if q_search == None:
q_search = new_q
else:
q_search = (q_search) | (new_q)
if '5' in threshold:
new_q = Q(delicious_threshold__lte = user.profile.taste_tolerance)
if q_search == None:
q_search = new_q
else:
q_search = (q_search) | (new_q)
return q_search
基本上,我希望用户能够找到满足给定阈值水平的某个对象的所有实例。所以,例如,所有他们会觉得不好的冰淇淋和所有他们会觉得好吃的冰淇淋。
我对这段代码有很多不满意的地方。我不喜欢检查Q对象是否还没有为每个可能的阈值实例化,但也没有找到绕过它的方法。此外,如果这是一个非django问题,我会使用一个循环来检查每个给定的阈值,而不是把每个阈值都写出来。但是,我也不知道该怎么做。
最后,最大的问题是,我需要检查模型的大约20个不同属性的阈值。按照目前的情况,我必须为每一个都编写一个新的阈值检查器,每一个都与另一个略有不同(它们正在检查的属性的名称)。我希望能够编写一个通用的检查器,然后将特定的属性传递给它。有什么办法能解决这个问题,还有我的另外两个问题吗?
谢谢!
这个方法怎么样?
query_arg = ['bad_threshold__lte', 'bad_threshold__lte', 'okay_threshold_3__lte', 'tasty_threshold__lte', 'delicious_threshold__lte']
Q(**{query_arg[int(threshold) - 1]: user.profile.taste_tolerance})
您应该使用自己的QuerySet
来代替def taste_threshold_set(...)
的例子:
models.py: ... from django.db.models.query import QuerySet ... class IcecreamManager(models.Manager): def get_query_set(self): return self.model.QuerySet(self.model) def __getattr__(self, attr, *args): try: return getattr(self.__class__, attr, *args) except AttributeError: return getattr(self.get_query_set(), attr, *args) class Icecream(models.Model()): name = models.CharField() bad_threshold = models.IntegerField() okay_threshold = models.IntegerField() tasty_threshold = models.IntegerField() delicious_threshold = models.IntegerField() objects = IcecreamManager() class QuerySet(QuerySet): def name_custom_method(self, arg1, argN): # you must rewrite for you solution return self.exclude( time_end__gt=now() ).filter( Q(...) | Q(...) ) def name_custom_method2(...) ...