Почему мне нужно выполнить второй цикл, чтобы получить значение 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}"