2016-06-30 3 views
4

私はDjangoアプリケーションでいくつかのQuerysetアクションを実行し、その結果をMemcacheに設定する機能を持っています。それは関数なので一般的な使い方でなければなりません。したがって、再利用可能にするために、私はfilterexcludeアクションのパラメータとしてdictを渡します。私は{'title': 'foo', 'name': 'bar'}のような単純な辞書でクエリセットをフィルタリングする場合、それはかなりうまく動作しますdict引数を使用したOR条件のDjangoフィルタ

def cached_query(key, model, my_filter=None, exclude=None, order_by=None, sliced=50): 
    """ 
    :param key: string used as key reference to store on Memcached 
    :param model: model reference on which 'filter' will be called 
    :param my_filter: dictionary containing the filter parameters (eg.: {'title': 'foo', 'category': 'bar'} 
    :param sliced: integer limit of results from the query. The lower the better, since for some reason Django Memcached 
     won't store thousands of entries in memory 
    :param exclude: dictionary containing the exclude parameters (eg.: {'title': 'foo', 'category': 'bar'} 
    :param order_by: tuple containing the list of fields upon which the model will be ordered. 
    :return: list of models. Not a QuerySet, since it was sliced. 
    """ 
    result = cache.get(key, None) 
    if not result: 
     if my_filter: 
      result = model.objects.filter(**my_filter) 
     if exclude: 
      result = result.exclude(**exclude) 
     if order_by: 
      result = result.order_by(*order_by) 
     else: 
      result = model.objects.all() 
     result = result[:sliced] 
     cache.set(key, result, cache_timeout) 
    return result 

:これは、関数です。しかし、それは必ずしもそうではありません。 OR条件を必要とするより複雑なクエリに対しては、django.db.models.Qユーティリティを使用してフィルタを実行する必要があります。

どのようにこれらのパラメータをフィルタの辞書として渡すことができますか。このためのアプローチはありますか?

答えて

6

あなたは、単一のキーと値の辞書のリストにあなたの辞書を再構築し、そのようなQ式の中の各dictに開梱を使用することができます。or_

from functools import reduce 
import operator 

from django.db.models import Q 

# your dict is my_filter 
q = model.objects.filter(reduce(operator.or_, 
           (Q(**d) for d in [dict([i]) for i in my_filter.items()]))) 

reduceはORにQ式を結合します。

また、あなたがlistdictのS持つジェネレータ式を使用できます。あなたはビット単位|演算子を使用することができます

q = model.objects.filter(reduce(operator.or_, 
           (Q(**d) for d in (dict([i]) for i in my_filter.items())))) 
3

を。これを考慮して

my_filter = Q() 

# Or the Q object with the ones remaining in the list 
my_or_filters = {'some_field__gte':3.5, 'another_field':'Dick Perch'} 

for item in my_or_filters: 
    my_filter |= Q(**{item:my_or_filters[item]}) 

model.objects.filter(my_filter) 
# unpacks to model.objects.filter(Q(some_field__gte=3.5) | Q(another_field='Dick Perch')) 

、あなたはmy_filterQにオブジェクトに保存されているすべてのクエリをロードすることもできます。 my_filter & = ...

+0

'item'キーワードに 'key error'がスローされます。 – Mauricio

+0

申し訳ありませんが、引用符で囲まれています。上記のようにしてください。 –

0

@Moses Koledoyeの答えに基づいて、私は問題を解決することができます:次に、あなたはビット単位& /ワット上記と同じ方法を経由して、すべての非ORクエリに参加することができます。これは私の機能が今のようになります:

cached_query(key, model, my_filter=None, or_filter={}, exclude=None, order_by=None, sliced=50): 
    """ 
    :param key: string used as key reference to store on Memcached 
    :param model: model reference on which 'filter' will be called 
    :param my_filter: dictionary containing the filter parameters (eg.: {'title': 'foo', 'category': 'bar'} 
    :param or_filter: dictionary containing the filter parameters (eg.: {'title': 'foo', 'category': 'bar'} 
    :param sliced: integer limit of results from the query. The lower the better, since for some reason Django Memcached 
     won't store thousands of entries in memory 
    :param exclude: dictionary containing the exclude parameters (eg.: {'title': 'foo', 'category': 'bar'} 
    :param order_by: tuple containing the list of fields upon which the model will be ordered. 
    :return: list of models. Not a QuerySet, since it was sliced. 
    """ 

    result = cache.get(key, None) 
    if not result: 
     result = model.objects.all() 
     if my_filter: 
      result = model.objects.filter(**my_filter) 
     if or_filter: 
      reduced_filter = reduce(operator.or_, (Q(**d) for d in [dict([i]) for i in or_filter.items()])) 
      result = result.filter(reduced_filter) 
     if exclude: 
      result = result.exclude(**exclude) 
     if order_by: 
      result = result.order_by(*order_by) 
     result = result[:sliced] 
     cache.set(key, result, cache_timeout) 
    return result 
関連する問題