у меня есть эти модели
class Protocol(models.Model):
name = models.CharField(max_length=200)
class Description(models.Model):
name = models.CharField(max_length=200)
protocol = models.ForeignKey(Protocol)
class Trait(models.Model):
desc = models.CharField(max_length=200)
protocol = models.ForeignKey(Protocol)
class State(models.Model):
desc = models.CharField(max_length=200)
trait = models.ForeignKey(Trait)
class Expression(models.Model):
state = models.ForeignKey(State)
description = models.ForeignKey(Description)
Таким образом, протокол (например, протокол «А») состоит из определенного количества признаков (например, рост, вес, цвет). Каждая черта может иметь несколько состояний (например, низкое, среднее, высокое). Затем описание представляет собой набор выражений, связанных с конкретным протоколом. Например, Описание №1 составлено по протоколу «А» и состоит из двух выражений: рост -> низкий, вес -> высокий; но цвет признака не указан.
По сути, я хочу отобразить в представлении шаблона все признаки, связанные с конкретным протоколом выбранного описания, а затем соответствующее выражение, которое также может быть пустым для некоторого признака.
Так:
| Trait | Expression |
|--------+------------|
| height | |
| weight | high |
| color | blue |
Используя оболочку, я могу легко вернуть то, что мне нужно
# Select a Description
desc = Description.objects.first()
# Get the protocol
protocol = desc.protocol
# Get all traits in the selected protocol
all_traits = protocol.trait_set.all()
# Get all the expressions in this description
expressions = desc.expression_set.all()
# Print all traits within the selected protocol and their related expression (if any)
for trait in all_traits:
print(trait.desc)
expr = expressions.filter(state__trait_id = trait.id).first()
print(expr.state.desc)
Однако я не могу понять, как это сделать в представлении, особенно я хотел бы продолжать использовать DetailView, но это не является строгим требованием, если это невозможно. Там в любом случае?
Спасибо
Я нашел способ сделать это, хотя я не полностью удовлетворен, потому что я чувствую, что это не очень элегантное решение.
Я создал description_extras.py
в каталоге templatetags/
внутри своего приложения (не забудьте __init__.py
рассматривать его как пакет)
Внутри description_extras.py
я создал собственный фильтр, например:
from django import template
register = template.Library()
@register.filter
def expr_trait(expression,trait_id):
return expression.filter(state__trait_id = trait_id).first()
Затем в шаблоне я загружаю пользовательский фильтр с помощью
{% load description_extras %}
И тогда я могу вызвать фильтр следующим образом:
{% for trait in description.protocol.trait_set.all %}
<tr>
<td>{{ trait.desc }}</td>
<td>{{ description.expression_set.all|expr_trait:trait.id }}</td>
</tr>
{% endfor %}