Django - Как сделать распаковку кортежа в цикле for шаблона

В моем views.py я создаю список из двух кортежей, где вторым элементом в кортеже является другой список, например:

[ Product_Type_1, [ product_1, product_2 ],
  Product_Type_2, [ product_3, product_4 ]]

В простом старом Python я мог бы повторить список следующим образом:

for product_type, products in list:
    print product_type
    for product in products:
        print product

Кажется, я не могу сделать то же самое в своем шаблоне Django:

{% for product_type, products in product_list %}
    print product_type
    {% for product in products %}
        print product
    {% endfor %}
{% endfor %}

Я получаю эту ошибку от Django:

Обнаружено исключение при рендеринге: аргумент zip №2 должен поддерживать итерацию

Конечно, в шаблоне есть HTML-разметка, а не операторы печати. Распаковка кортежей не поддерживается в языке шаблонов Django? Или я иду об этом неправильно? Все, что я пытаюсь сделать, это отобразить простую иерархию объектов — есть несколько типов продуктов, каждый из которых имеет несколько продуктов (в models.py Product имеет внешний ключ для Product_type, простое отношение «один ко многим»).

Очевидно, я новичок в Django, поэтому любой вклад будет оценен.


person Chris Lawlor    schedule 07.11.2008    source источник
comment
Вы говорите о кортежах, но ваш вопрос содержит только списки. Это разные вещи в питоне.   -  person Harley Holcombe    schedule 07.11.2008
comment
На самом деле у вас нет двух кортежей. Посмотрите внимательно на свой список, у вас есть 4 пункта списка. Как заметил Джонни Бьюкенен, вам нужно сделать это: [ [Product_Type_1, [ product_1, product_2 ], ], [Product_Type_2, [ product_3, product_4 ], ], ] чтобы получить версию списка из двух кортежей.   -  person MontyThreeCard    schedule 17.03.2017


Ответы (5)


было бы лучше, если бы вы построили свои данные следующим образом: {обратите внимание, что '(' и ')' можно заменить на '[' и ']' соответственно, один для кортежей, другой для списков}

[ (Product_Type_1, ( product_1, product_2 )),
   (Product_Type_2, ( product_3, product_4 )) ]

и пусть шаблон сделает это:

{% for product_type, products in product_type_list %}
    {{ product_type }}
    {% for product in products %}
        {{ product }}
    {% endfor %}
{% endfor %}

способ распаковки кортежей/списков в циклах for основан на элементе, возвращаемом итератором списка. на каждой итерации возвращался только один элемент. первый раз в цикле Product_Type_1, второй ваш список продуктов...

person Jake    schedule 07.11.2008
comment
то есть вы думали, что строите список из двух кортежей, но вы забыли часть кортежа - обратите внимание на дополнительные круглые скобки, окружающие пары типа продукта/списка продуктов в ответе Шифра - person Jonny Buchanan; 07.11.2008
comment
Это не работает для более старых версий Django (например, той, что используется в GAE). Используйте ответ Эшвина Рао, если вы получите эту ошибку: операторы «для» с пятью словами должны заканчиваться на «обратный» - person Franziskus Karsunke; 01.08.2011

Другой способ заключается в следующем.

Если у вас есть список кортежей, скажите:

mylst = [(a, b, c), (x, y, z), (l, m, n)]

то можно распаковать этот список в файл шаблона следующим образом. В моем случае у меня был список кортежей, содержащих URL-адрес, заголовок и сводку документа.

{% for item in mylst %}    
     {{ item.0 }} {{ item.1}} {{ item.2 }}    
{% endfor %}
person Ashwin Rao    schedule 21.01.2011
comment
.0 ... совсем не интуитивно понятно. - person Iulius Curt; 04.06.2014
comment
Трюк @iuliux заключается в том, чтобы помнить, что язык шаблонов заставляет . означать что угодно, от доступа к переменным до подписки, вызова метода, все с одним и тем же синтаксисом ... Тем не менее согласен с вами, хотя :) - person mccc; 12.12.2014
comment
Почему косая черта \ там? - person J0ANMM; 01.02.2017

Вы должны использовать этот путь:

{% for product_type, products in product_list.items %}
    print product_type
    {% for product in products %}
        print product
    {% endfor %}
{% endfor %}

Не забывайте переменные элементы в данных словаря

person Community    schedule 22.07.2009
comment
Наконец, ответ, который я искал. Спасибо! - person Teekin; 29.07.2015

Если у вас есть фиксированное число в ваших кортежах, вы можете просто использовать индексацию. Мне нужно было смешать словарь, а значения были кортежами, поэтому я сделал так:

В представлении:

my_dict = {'parrot': ('dead', 'stone'), 'lumberjack': ('sleep_all_night', 'work_all_day')}

В шаблоне:

<select>
  {% for key, tuple in my_dict.items %}
    <option value="{{ key }}" important-attr="{{ tuple.0 }}">{{ tuple.1 }}</option>
  {% endfor %}
</select>
person famousfilm    schedule 19.02.2016

Просто отправьте шаблону список типов продуктов и сделайте что-то вроде:

{% for product_type in product_type_list %}
    {{ product_type }}
    {% for product in product_type.products.all %}
        {{ product }}
    {% endfor %}
{% endfor %}

Прошло немного времени, поэтому я не могу точно вспомнить, что такое синтаксис, дайте мне знать, если это сработает. Ознакомьтесь с документацией.

person Harley Holcombe    schedule 07.11.2008
comment
Крис Лоулор не объяснил, как он получил структуру данных, которая у него есть (которая на самом деле не является списком из двух кортежей), но этот предлагаемый подход приведет к N + 1 запросам для отображения списка продуктов. - person Jonny Buchanan; 07.11.2008
comment
Вот драконы. Используя это предложение, вы совершаете отдельный поход в базу данных для каждого product_type. Я подозреваю, что минимизация нагрузки на базу данных, вероятно, является мотивацией использования кортежей в первую очередь. - person btubbs; 03.12.2009
comment
Я думаю, вы могли бы использовать select_related(), чтобы смягчить эту конкретную проблему, верно? - person Charles Offenbacher; 16.04.2011