2016-09-28 8 views
2

Я читаю this article о динамически генерирующих Q объектах. Я понимаю (по большей части) объектов Q, но я не понимая, как автор конкретно делает этот пример:Понимание Django Q - Dynamic

# string representation of our queries 
>>> predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')] 

# create the list of Q objects and run the queries as above.. 
>>> q_list = [Q(x) for x in predicates] 

>>> Poll.objects.filter(reduce(operator.or_, q_list)) 
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>] 

Что я конкретно не получаю список понимание. Объект Q отформатирован с произвольными ключевыми аргументами как таковые Q(question__contains='dinner').

Если вы делаете это, как предлагает автор со списком, не так ли эффективно разместить кортеж внутри объекта Q на каждой итерации? Например: Q(('question__contains', 'dinner')).

Я не уверен, как этот код создает правильно отформатированный объект Q.

ответ

4

Статья ссылается на недокументированную функцию, которую Q() принимает как args, так и kwargs.

Если вы посмотрите на source code for the Q class, вы можете увидеть, что он выполняет следующие функции в методе __init__.

class Q(tree.Node): 
    ... 
    def __init__(self, *args, **kwargs): 
     super(Q, self).__init__(children=list(args) + list(kwargs.items())) 

Если вы звоните Q(question__contains=dinner) затем args в пустой кортеж () и kwargs является словарь {'question__contains': 'dinner'}. В super() вызова, переменная children является

children = list(args) + list(kwargs.items()) 

, который вычисляет

children = list(()) + list(('question__contains', 'dinner'),) 

, который упрощает для

children = [('question__contains', 'dinner')] 

Обратите внимание, что вы можете также получить этот результат, если вы используете Q(('question__contains', 'dinner')). В этом случае args является кортежем (('question__contains', 'dinner'),) и kwargs является пустым словарем {}.

В super() вызова, переменная children вычисляет

children = list((('question__contains', 'dinner'),)) + list([]) 

, который упрощает к тому же результату, как и прежде,

children = [('question__contains', 'dinner')] 

Мы показали, что Q(question__contains=dinner) эквивалентно Q(('question__contains', 'dinner')), и поэтому вы может сгенерировать список объектов Q(), перейдя по списку из 2-х кортежей в понимании списка.

>>> predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')] 
>>> q_list = [Q(x) for x in predicates] 

Лично я бы предпочел, чтобы написать

>>> predicates = [{'question__contains': 'dinner'}, {'question__contains': 'meal'}] 
>>> q_list = [Q(**kwargs) for kwargs in predicates] 

Таким образом, вы не полагаясь на поведение __init__ метода в Q.

+0

Абсолютно здорово. Большое спасибо за то, что он прошел через него. – qarthandso