Почему мне нужно выполнить второй цикл, чтобы получить значение sigle в django?

Проект заключался в создании страницы фильтрации, где пользователи могут фильтровать данные модели на основе выбранных ими критериев. Все работает, но определенная часть не ясна и не имеет смысла.

Вот моя модель -

class Author(models.Model):
    name=models.CharField(max_length=30)

    def __str__(self):
        return self.name

class Kategory(models.Model):
    name=models.CharField(max_length=20)

    def __str__(self):
        return self.name        


class Data(models.Model):
    title=models.CharField(max_length=120)
    author=models.ForeignKey(Author, on_delete=models.CASCADE)
    categories=models.ManyToManyField(Kategory)
    publish_date=models.DateTimeField()
    views=models.IntegerField(default=0)
    reviewed=models.BooleanField(default=False)

    def __str__(self):
        return self.title

Data является основной моделью, а Author был добавлен как ForeignKey и Kategory как многие ко многим полям. Моя основная проблема связана с полем categories в модели Data, которое имеет отношения многие-ко-многим с моделью Kategory.

Вот мой файл views.py-

# This view is for the filter page

def is_valid_queryparam(param):
    return param !='' and param is not None

def filter(request):
    qs=Data.objects.all()
    kategory=Kategory.objects.all()
    title_contains_query=request.GET.get('title_contains')
    id_exact_query=request.GET.get('id_exact')
    title_or_author_query=request.GET.get('title_or_author')
    view_count_min=request.GET.get('view_count_min')
    view_count_max=request.GET.get('view_count_max')
    date_min=request.GET.get('date_min')
    date_max=request.GET.get('date_max')
    category=request.GET.get('category')

    if is_valid_queryparam(title_contains_query):
        qs=qs.filter(title__icontains=title_contains_query)

    if is_valid_queryparam(id_exact_query):
        qs=qs.filter(id=id_exact_query)

    if is_valid_queryparam(title_or_author_query):
        qs=qs.filter(Q(title__icontains=title_or_author_query) | Q(author__name__icontains=title_or_author_query))

    if is_valid_queryparam(view_count_min):
        qs=qs.filter(views__gte=view_count_min)   

    if is_valid_queryparam(view_count_max):
        qs=qs.filter(views__lte=view_count_max)

    if is_valid_queryparam(date_min):
        qs=qs.filter(publish_date__gte=date_min)

    if is_valid_queryparam(date_max):
        qs=qs.filter(publish_date__lte=date_max)

    if is_valid_queryparam(category):
        qs=qs.filter(categories=category)     

    test=Data.objects.only('author')

    context={'queryset':qs, 'kategory':kategory, 'test':test}    

    return render(request, 'myapp/filter.html', context)

Как вы можете видеть в файле views.py, у меня есть 2 переменные, хранящие все данные модели Data и Kategory. Я уже много раз работал с подобными вещами. При отображении данных в таблице на шаблоне django мы просто запускаем цикл for. В этот раз я просто не могу получить переменную в поле категорий. Все остальные поля работают нормально. Вместо того, чтобы выдать мне значение, выводится None или myapp.kategory.none или что-то подобное. Мне пришлось запустить дополнительный цикл, чтобы получить значение категории. Я просто не могу понять, почему я должен запускать этот дополнительный цикл, чтобы получить значение. Если кто-нибудь может пролить свет на это и объяснить немного, или даже привести меня к литературе, которая объясняет это, это было бы полезно.

Ниже приведен код шаблона, чтобы показать вам дополнительный цикл, который я запускаю. Посмотрите на 3-й тег, чтобы увидеть дополнительный цикл. Я должен получить значение просто по journal.categories. Почему мне нужно запускать этот цикл?

<table class="three">
    <tr >
        <th>Title</th>
        <th>Author</th>
        <th>Category</th>
        <th>Views</th>
        <th>Date Published</th>
        
        
    </tr>
    
    {% for journal in queryset %}
        
    
        <tr >
            <td>{{ journal.title }}</td>
            <td>{{ journal.author }}</td>
            <td>{% for cat in journal.categories.all %}
              {{ cat }}
            {% endfor %}</td>
            <td>{{ journal.views }}</td>
            <td>{{ journal.publish_date }}</td>
            
            
           
        </tr>    
        {% endfor %}    
</table>

Вы не определили ForeignKey.related_name, поэтому следует использовать значение по умолчанию, так:

<table class="three">
    <tr>
        <th>Title</th>
        <th>Author</th>
        <th>Category</th>
        <th>Views</th>
        <th>Date Published</th>
        
        
    </tr>
    
    {% for journal in queryset %}
        
    
        <tr>
            <td>{{ journal.title }}</td>
            <td>{{ journal.author }}</td>
            <td>{% for cat in journal.categories %}
              {{ cat }}
            {% endfor %}</td>
            <td>{{ journal.views }}</td>
            <td>{{ journal.publish_date }}</td>
            
            
           
        </tr>    
        {% endfor %}    
</table>

Дополнительно я бы рекомендовал вам использовать f-stings в __str__() методе моделей так:

class Author(models.Model):
    name=models.CharField(max_length=30)

    def __str__(self):
        return f"{self.name}"

class Kategory(models.Model):
    name=models.CharField(max_length=20)

    def __str__(self):
        return f"{self.name}"        


class Data(models.Model):
    title=models.CharField(max_length=120)
    author=models.ForeignKey(Author, on_delete=models.CASCADE)
    categories=models.ManyToManyField(Kategory)
    publish_date=models.DateTimeField()
    views=models.IntegerField(default=0)
    reviewed=models.BooleanField(default=False)

    def __str__(self):
        return f"{self.title}"
Вернуться на верх