Как получить доступ ко многим полям без цикла внутри шаблона

#django #django-models

Вопрос:

У меня есть следующие модели, определенные для моих портфельных проектов:

 class Technology(models.Model):
    title = models.CharField(max_length=10)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = 'Technologies'


class Project(models.Model):
    title = models.CharField(max_length=100)
    description = HTMLField()
    technology = models.ManyToManyField(Technology)
    image = models.ImageField(upload_to='projects/')

    def __str__(self):
        return self.title
 

И у меня есть это в моем views.py :

 def index(request):
    projects = Project.objects.all()
    context = {'projects': projects}
    return render(request, 'homepage/index.html', context)
 

И следующий фрагмент HTML для отображения проектов:

 {% for project in projects %}
<div class="col-lg-4 col-md-6 portfolio-item filter-django">
    <div class="portfolio-wrap">
        <img src="{% static 'homepage/img/portfolio/portfolio-1.jpg' %}" class="img-fluid">         
        <div class="portfolio-info">
            <h4>{{ project.title }}</h4>
            <p>FIRST TECHNOLOGY GOES HERE</p>
        </div>
    </div>
</div>
{% endfor %}
 

Моя проблема заключается в <p>...</p> теге, потому что в каждом проекте есть несколько технологий, но мне нужно напечатать только первую, чтобы у меня не было for loop здесь.

Я пытался {{ project.technology.[0] }} , но это дает мне Could not parse the remainder: '[0]' from 'project.technology.[0]'

Пожалуйста, помогите.

Комментарии:

1. Использовать project.technology.first (предпочтительно) или project.technology.0

Ответ №1:

Язык шаблонов Django (DTL) не поддерживает различный сложный синтаксис, который поддерживает python. Это сделано намеренно, потому что одна из целей DTL-отделить бизнес-логику от логики представления. Следовательно {{ project.technology.[0] }} , не работает. Но вместо этого все виды поиска могут выполняться с помощью самого . оператора, что означает, что вы можете написать {{ project.technology.all.0 }} (здесь, поскольку all он вызывается, он будет вызываться механизмом шаблонов) для достижения того же эффекта, что и индексирование.

Но вместо этого вы должны использовать метод first [Django docs] набора запросов, который даст вам либо первый объект, либо None ( [0] индексирование может вызвать исключение, если результирующий запрос ничего не возвращает).:

 {% for project in projects %}
<div class="col-lg-4 col-md-6 portfolio-item filter-django">
    <div class="portfolio-wrap">
        <img src="{% static 'homepage/img/portfolio/portfolio-1.jpg' %}" class="img-fluid">         
        <div class="portfolio-info">
            <h4>{{ project.title }}</h4>
            {% with first_technology=project.technology.first %}
                {% if first_technology is not None %}
                    <p>{{ first_technology }}</p>
                {% else %}
                    <p>No technology</p>
                {% endif %}
            {% endwith %}
        </div>
    </div>
</div>
{% endfor %}
 

Комментарии:

1. Спасибо. Моя проблема решена. Просто скажите мне, почему project.technology.first работает (возвращает первую технологию), но project.technology.0 ничего не возвращает?

2. @OmidShojaee О, подождите, это должно быть project.technology.all.0 так, как project.technology просто связанный менеджер, а не набор запросов.