Как показать ссылки на категорию с помощью Django
Я кодирую проект закладки, чтобы изучить django. Я хочу показывать ссылки, относящиеся к категории. но когда я запускаю цикл for, категории показываются дважды, а дизайн карточек сортируется одна под другой, а не бок о бок. Я думаю, что проблема в файле index.html. Я думаю, что мне нужно использовать команду if, но не знаю как.
index.html
views.py
def index(request):
bookmark_list = Bookmarks.objects.all()
return render(request,"index.html",{'bookmark_list':bookmark_list})
models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Meta:
db_table = ''
managed = True
verbose_name = 'Category'
verbose_name_plural = 'Categorys'
# Create your models here.
class Bookmarks(models.Model):
title = models.CharField( max_length=50)
category = models.ForeignKey(Category, null=True, on_delete=models.DO_NOTHING)
description = models.TextField(max_length=1000,blank=True)
link = models.URLField(max_length=400)
date = models.DateField(auto_now=True)
def __str__(self):
return self.title
введите описание изображения здесь
Мне кажется, я вижу две отдельные проблемы:
1. Отображение всех ссылок на закладки на одной карточке, сгруппированных по категориям
Для достижения этой цели можно использовать набор вложенных циклов {% for %}. Сейчас вы передаете bookmarks как объект в шаблон, что хорошо, но затрудняет группировку по категориям. Вы можете получить доступ к связанному набору Bookmarks из каждого Category гораздо проще. Я рекомендую изменить ваш views.py на что-то вроде следующего:
# views.py
#=====================================================================
def index(request):
categories = Category.objects.all()
return render(request,"index.html",{'categories':categories})
Затем, внутри вашего шаблона, вы можете установить вложенный цикл следующим образом:
<!--index.html-->
<!--===============================================================-->
{% comment %} The first 'for' loop makes a card with the category's
name as a heading {% endcomment %}
{% for category in categories %}
<div class="px-6 xl:px-0">
<div class="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 pb-6 gap-8">
<div role="cell" class="bg-gray-100">
<div class="bg-white p-5 rounded-md relative h-full w-full">
<h1 class="pb-4 text-2xl font-semibold">{{ category.name }}</h1>
{% comment %} The nested 'for' loop goes through each bookmark that is
related to the category on this card is dedicated to {% endcomment %}
{% for bookmark in category.bookmark_set.all %}
<div class="my-5">
<div class="flex items-center pb-4 dark:border-gray-700 cursor-pointer w-full space-x-3">
<svg xmlns="http://www.w3.org/2000/svg" width="12.5" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<a href="{{bookmark.link}}">
<h4 class="text-md text-gray-900 dark:text-gray-100" data-bs-toggle="tooltip" data-bs-placement="right" title="{{bookmark.description}}">
{{bookmark.title}}
</h4>
</a>
</div>
</div>
{% endfor %}
<a class="hover:text-indigo-500 hover:underline absolute bottom-5 text-sm text-indigo-700 font-bold cursor-pointer flex items-center" href="javascript:void(0)">
<p>Show All</p>
<div>
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-narrow-right" width="16" height="16" viewBox="0 0 24 24" stroke-width="1.5" stroke="#4338CA" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<line x1="5" y1="12" x2="19" y2="12" />
<line x1="15" y1="16" x2="19" y2="12" />
<line x1="15" y1="8" x2="19" y2="12" />
</svg>
</div>
</a>
</div>
</div>
</div>
</div>
{% endfor %}
По сути, category.bookmark_set.all использует отношение внешнего ключа для получения отфильтрованного списка всех закладок, относящихся к заданной категории. Документация Django рассказывает больше о том, как это работает здесь: https://docs.djangoproject.com/en/dev/ref/templates/language/#accessing-method-calls
Недостатки
<<<Исходя из вашего, если у вас есть models.py с нулевым внешним ключом, он не будет отображен, поскольку он не только не принадлежит Bookmark, но и вообще не имеет отношения к Category. Одним из способов решения этой проблемы может быть создание универсального Category под названием "None" или что-то в этом роде. Затем вы можете добавить Category, указывающий на default вашей категории "None" в pk. Это будет означать, что даже если закладка будет создана без явного создания пользователем категории, она будет автоматически отнесена к категории "None".Bookmark.category
Кроме того, поскольку on_delete = models.DO_NOTHING для вашего Bookmark, если вы удалите Category, к которому принадлежит Bookmark, Bookmark не будет отображаться, поскольку он будет иметь отношение к Category, которого не существует. Это может вызвать проблемы с целостностью базы данных. Поскольку ваш Bookmark.category может быть установлен в null, я рекомендую (по крайней мере) установить вместо него on_delete = models.SET_NULL. Если вы решили использовать универсальную категорию "None", я бы установил on_delete = models.SET(<pk>), где <pk> - первичный ключ "None" Category. Если вы решили добавить значение по умолчанию для Bookmark.category, вы также можете установить on_delete = models.SET_DEFAULT. Вы можете прочитать больше об этом в документации Django здесь: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.on_delete
2. Раскладывание карт слева направо
Я не уверен, какой фреймворк вы используете для своих HTML-классов, но причина того, что ваш макет не работает так, как вы хотите, почти наверняка кроется там. Если вы используете Bootstrap, вы можете сделать следующее; если нет, надеюсь, это поможет вам понять, как можно добиться того же самого.
Bootstrap использует 12-колоночную систему сетки для макетов. Вы должны быть в состоянии заставить ваши карточки отображаться слева направо в три колонки, выполнив следующие действия:
<!--index.html-->
<!--===============================================================-->
<div class="container">
<div class="row">
{% comment %} Add a <div> node INSIDE the first 'for' loop {% endcomment %}
{% for category in categories %}
<div class="col-4">
<!--Card code goes here; remember, you don't want 3 'for' loops;
just 2!-->
<div class="px-6 xl:px-0">
<div class="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 pb-6 gap-8">
<div role="cell" class="bg-gray-100">
<div class="bg-white p-5 rounded-md relative h-full w-full">
<h1 class="pb-4 text-2xl font-semibold">
{{ category.name }}
</h1>
{% comment %} The nested 'for' loop goes through each bookmark that is
related to the category on this card is dedicated to {% endcomment %}
{% for bookmark in category.bookmark_set.all %}
<div class="my-5">
<div class="flex items-center pb-4 dark:border-gray-700 cursor-pointer w-full space-x-3">
<svg xmlns="http://www.w3.org/2000/svg" width="12.5" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<a href="{{bookmark.link}}">
<h4 class="text-md text-gray-900 dark:text-gray-100" data-bs-toggle="tooltip" data-bs-placement="right" title="{{bookmark.description}}">
{{bookmark.title}}
</h4>
</a>
</div>
</div>
{% endfor %}
<a class="hover:text-indigo-500 hover:underline absolute bottom-5 text-sm text-indigo-700 font-bold cursor-pointer flex items-center" href="javascript:void(0)">
<p>Show All</p>
<div>
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-narrow-right" width="16" height="16" viewBox="0 0 24 24" stroke-width="1.5" stroke="#4338CA" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<line x1="5" y1="12" x2="19" y2="12" />
<line x1="15" y1="16" x2="19" y2="12" />
<line x1="15" y1="8" x2="19" y2="12" />
</svg>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
Класс col-4 создает колонку шириной 4 из 12 колонок Bootstrap. Это означает, что независимо от ширины экрана на экране всегда будет 3 колонки. Похоже, что вы пытаетесь создать отзывчивую страницу, которая уменьшает количество колонок в зависимости от размера экрана; в документации Bootstrap описано, как это сделать: https://getbootstrap.com/docs/5.1/layout/grid/
Вы не обязаны использовать Bootstrap (и это ни в коем случае не реклама его), просто я лучше всего знаком с тем, как настроить подобный макет с помощью Bootstrap. Похоже, что класс grid на одном из узлов <div> делает что-то похожее на это; любой фреймворк, который вы используете, вероятно, документирует способ принудительной схемы расположения слева направо-вниз (а не сверху-вниз-вправо).