Работа мечты в один клик 💼

💭Мечтаешь работать в Сбере, но не хочешь проходить десять кругов HR-собеседований? Теперь это проще, чем когда-либо!
💡AI-интервью за 15 минут – и ты уже на шаг ближе к своей новой работе.
Как получить оффер? 📌 Зарегистрируйся 📌 Пройди AI-интервью 📌 Получи обратную связь сразу же!
HR больше не тянут время – рекрутеры свяжутся с тобой в течение двух дней! 🚀
Реклама. ПАО СБЕРБАНК, ИНН 7707083893. Erid 2VtzquscAwp
Это достаточно сложный проект, состоящий из двух взаимосвязанных приложений – Projects и Users. Разработчики могут создавать профили и добавлять в портфолио проекты. Предусмотрены поиск, оценка проектов и обмен сообщениями. Реализована фильтрация по тегам (для проектов) и по скиллам (для профилей). Весь код проекта ITfinder находится здесь.
Обзор проекта
Сайт включает:
- Систему аутентификации и авторизации.
- Поиск по профилям, навыкам, тегам, описаниям проектов.
- Фильтрацию по тегам и скиллам.
- CRUD операции для создания, редактирования, удаления профилей, проектов, тегов и скиллов.
- Мессенджер.
- Систему оценок и отзывов о проектах.




Первый этап
Работа над Django проектом начинается с установки зависимостей, создания базовой структуры проекта и входящих в него приложений.
Установка Django и создание структуры проекта
Выполним установку фреймворка и зависимостей с помощью встроенного менеджера виртуального окружения venv:
python -m venv itfinder\venv
cd itfinder
venv\scripts\activate
pip install -r requirements.txt
Создадим новый проект под названием itfinder:
django-admin startproject itfinder
Проект состоит из двух приложений – «Проекты» и «Пользователи». Начнем работу с создания скелета проекта projects:
cd itfinder
python manage.py startapp projects
Django автоматически создает базовую структуру приложения, но зарегистрировать projects в конфигурационном файле проекта придется вручную. Откройте файл itfinder\settings.py, и добавьте в список INSTALLED_APPS строку 'projects.apps.ProjectsConfig'
.
Теперь нужно создать основные маршруты приложения «Проекты». Создайте файл projects/urls.py и сохраните в нем нужные маршруты:
from django.urls import path
from . import views
urlpatterns = [
path('', views.projects, name="projects"),
path('project-object/<str:pk>/', views.project, name="project"),
]
Чтобы маршруты projects были доступны на уровне проекта, нужно включить их в глобальные URL – в файле itfinder\urls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('projects.urls')),
]
Шаблоны приложения Projects
Создайте папку templates внутри projects, и в ней два файла – projects.html и single-project.html. Тестовый код для шаблона projects.html:
<!DOCTYPE html>
<html>
<head>
<title>Шаблон для вывода проектов</title>
</head>
<body>
<h2>Здесь будут все проекты</h2>
{% for project in projects %}
<p>Номер проекта: #{{ project.id }}</p>
<h3>Название проекта: <a href="{% url 'project' project.id %}">{{ project.title }}</a></h3>
<em>{{ project.description }}</em>
{% endfor %}
</body>
</html>
Для single-projects.html:
<!DOCTYPE html>
<html>
<head>
<title>Шаблон для отдельного проекта</title>
</head>
<body>
<h1>Подробная информация о проекте</h1>
<h3>Проект #{{ project.id }}</h3>
<p>{{ project.title }}</p>
<br>
<em>{{ project.description }}</em>
</body>
</html>
Добавим import os
и ссылку на шаблоны в файл настроек itfinder/settings.py:
'DIRS': [os.path.join(BASE_DIR, 'templates')],
Принцип работы Django основан на схеме MVT – (Модель, Представление, Шаблон). Если вам не приходилось раньше работать с Джанго, схему работы фреймворка может прояснить приведенный ниже пример того, как функция представления передает данные в шаблон, который мы только что создали. Напишем тестовые функции представления в файле projects/views.py:
from django.shortcuts import render
def projects(request):
projectsList = [{'id':'1',
'title':'Онлайн-кинотеатр',
'description':'Кинотеатр с самой полной библиотекой фильмов.'},
{'id':'2',
'title':'Платформа с ИТ-курсами',
'description':'Курсы по фронтенду, бэкенду и мобильной разработке.'},
{'id':'3',
'title':'Рекрутинговый портал',
'description':'Вакансии для специалистов экстра-класса.'},
]
return render(request, 'projects/projects.html', {'projects':projectsList})
def project(request):
return render(request, 'projects/single-project.html')
Запустите сервер python manage.py runserver
и откройте адреса http://localhost:8000/ и http://localhost:8000/project/ – все работает, функция передает в шаблон тестовые данные:

В реальных приложениях модели извлекают информацию из базы данных, а представления могут быть основаны не на функциях, а на классах.
База данных
Джанго по умолчанию работает с базой типа SQLite3 – настройки для подключения указаны в файле itfinder/settings.py. Для инициализации базы данных выполним команду python manage.py migrate
. Эта же команда используется для применения изменений, в дальнейшем мы будем ею пользоваться неоднократно, но уже в другом формате – после команды python manage.py makemigrations
, которая отслеживает все изменения в моделях.
После инициализации базы Джанго открывает доступ к панели администрирования – http://localhost:8000/admin. Однако для создания учетной записи администратора (суперпользователя) нужно выполнить еще одну команду:
python manage.py createsuperuser
В ходе создания аккаунта можно пропустить введение имени – тогда по умолчанию будет назначен юзернейм user, и емейла (поле останется пустым). Если сейчас войти в панель администрирования, можно отметить, что пока там можно создавать, изменять и удалять только новых пользователей и группы.

Для создания, редактирования и удаления других типов записей (профилей, проектов, комментариев) нужно сначала определить, а затем зарегистрировать в админ-панели нужные модели. Все атрибуты таблиц базы данных и взаимоотношения между ними определяются в файлах типа models.py. Модели представляют собой классы, все атрибуты которых ORM слой Django связывает с соответствующими полями таблиц. Благодаря этому отпадает необходимость использовать язык SQL.
Создадим нашу первую модель, которая будет хранить данные обо всех проектах, добавленных в раздел «Проекты». Это первый вариант модели, в дальнейшем мы ее расширим и дополним:
from django.db import models
import uuid
class Project(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
description = models.TextField(null=True, blank=True)
demo_link = models.CharField(max_length=500, null=True, blank=True)
source_link = models.CharField(max_length=500, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return self.title
После создания модели нужно подготовить миграции:
python manage.py makemigrations
И применить их к базе:
python manage.py migrate
Чтобы модель была доступна в панели администрирования, ее нужно зарегистрировать в файле itfinder/admin.py:
from django.contrib import admin
from .models import Project
admin.site.register(Project)
После регистрации форма добавления проектов становится доступной в панели администрирования:

В нашем приложении будет несколько моделей, связанных друг с другом различными способами:
- Один к одному – у одного пользователя может быть только один профиль.
- Один ко многим – один пользователь (профиль) может быть автором множества проектов; один проект может получить множество отзывов / комментариев / оценок. Для реализации такой связи служит
ForeignKey
. Установление связи между таблицами с помощью ForeignKey нуждается в дополнительных параметрах на случай удаления одной из таблиц. В случае с проектом и отзывами к нему этоCASCADE
– он удаляет отзыв в случае удаления проекта, к которому отзыв относился. - Многие ко многим – у одного проекта может быть множество тегов, а у пользователя – несколько навыков. Один и тот же тег (навык) может использоваться во множестве проектов (или профилей).
Связь проекта с тегами и отзывами
Расширим модель Project, добавив в нее связь с таблицами тегов и отзывов:
from django.db import models
import uuid
class Tag(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField()
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return self.name
class Project(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
description = models.TextField(null=True, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
total_votes = models.IntegerField(default=0, null=True, blank=True)
votes_ratio = models.IntegerField(default=0, null=True, blank=True)
demo_link = models.CharField(max_length=500, null=True, blank=True)
source_link = models.CharField(max_length=500, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return self.title
class Review(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
VOTE_TYPE = (
('up', 'Up Vote'),
('down', 'Down Vote'),
)
review_text = models.TextField(null=True, blank=True)
value = models.CharField(max_length=200, choices=VOTE_TYPE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return self.value
Зарегистрируем новые модели в admin.py:
from django.contrib import admin
from .models import Project, Review, Tag
admin.site.register(Project)
admin.site.register(Review)
admin.site.register(Tag)
Выполним миграции и откроем админ-панель – теперь к проектам можно добавлять теги, рейтинг и отзывы:

Создайте несколько проектов или воспользуйтесь готовой базой данных. Эта информация нам понадобится для реализации следующего шага – запросов.
Запросы к базе данных
Структура запроса к базе данных в Джанго выглядит так:
Queryset = ModelName.objects.all()
- где Queryset – переменная, которой передаются результаты запроса;
- ModelName – название модели;
- objects – атрибут объекта модели;
- all() – метод.
Кроме all(), который возвращает все объекты модели, есть множество других методов, например:
- filter, filter_by – фильтруют по значениям атрибутов. При этом значение может быть равно запросу, содержать ключевое слово или начинаться с определенного критерия. Фильтры могут учитывать или игнорировать регистр.
- icontains – проверяет, содержит ли поле определенный запрос.
- get – возвращает единичный объект;
- exclude – исключает определенные значения.
Тестировать запросы удобно в интерактивной консоли, которую запускают командой python manage.py shell
:
python manage.py shell
>>> from projects.models import Project
>>> projects = Project.objects.all()
>>> print(projects)
<QuerySet [<Project: EverGreen - магазин люксовой эко-косметики>, <Project: ITGi
gs - платформа для поиска ИТ-фрилансеров>, <Project: BlahBlahChat - социальная с
еть нового поколения>, <Project: RoboShop - магазин электронных игрушек>, <Proje
ct: SuperCook - сайт для кулинарного блогера>]>
>>> singleproject = Project.objects.get(title='RoboShop - магазин электронных иг
рушек')
>>> print(singleproject)
RoboShop - магазин электронных игрушек
>>> print(singleproject.created)
2022-07-05 15:40:34.240616+00:00
>>> print(singleproject.slug)
roboshop-magazin-igrushek
>>> exit()
Передача данных из базы в шаблон
Откройте файл itfinder/views.py, добавьте в него импорт моделей:
from .models import Project
И измените функцию представления projects на эту:
def projects(request):
projects = Project.objects.all()
context = {'projects': projects}
return render(request, 'projects/projects.html', context)
Функция представления отдельного проекта теперь должна выглядеть так:
def project(request, pk):
projectObj = Project.objects.get(id=pk)
tags = projectObj.tags.all()
return render(request, 'projects/single-project.html', {'project': projectObj})
В шаблон для вывода отдельных проектов нужно добавить отображение тегов:
<!DOCTYPE html>
<html>
<head>
<title>Шаблон для отдельного проекта</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Подробная информация о проекте</h1>
<h3>Проект {{ project.id }}</h3>
<p>{{ project.title }}</p>
<br>
<ul>
{% for tag in project.tags.all %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
<em>{{ project.description }}</em>
</body>
</html>
Запустите сервер – на главной странице сайта появилось описание проектов из базы данных:

И описание отдельного проекта тоже выводится – с тегами:

Код и база данных для первого этапа – здесь.
Второй этап
Начнем с разработки CRUD – функциональности для создания, редактирования и удаления проектов.
Сначала сделаем шаблон для формы, которая будет использоваться как для создания, так и для редактирования проектов. Сохраните этот код в project_form.html:
{% block content %}
<h1>Информация о проекте</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="" value="Добавить проект">
</form>
{% endblock content %}
Токен csrf_token обеспечивает защиту сайта от атак; кроме того, без него форма просто не будет обрабатываться. Параметр .as_p
создает теги <p></p>
вокруг элементов формы.
Создайте файл itfinder\forms.py:
from django.forms import ModelForm
from .models import Project
class ProjectForm(ModelForm):
class Meta:
model = Project
fields = ['title', 'slug', 'tags', 'description', 'demo_link', 'source_link']
Во многих случаях вместо строки с перечислением полей можно указать fields = '__all__'
– тогда модуль ModelForm автоматически сгенерирует форму на основе модели проекта, и перечислять поля по отдельности не придется. При этом модуль проигнорирует поля, которые не подлежат редактированию (как уникальный UUID), и пропустит поля, создаваемые во время сохранения записи (как created
). Однако в нашей модели Project есть поля, которые обновляются при подсчете рейтинга, и пользователи не должны иметь доступа к ним, поэтому в форме мы перечисляем только редактируемые поля.
Добавьте ссылку на создание проекта в шаблон projects.html:
<strong><a href="{% url 'create-project' %}">Добавить проект</a></strong>
Перезагрузите страницу – форма создания нового проекта благополучно загружается, хотя пока что не имеет никакого дизайна (и ничего не сохраняет):

Чтобы форма сохраняла данные, внесем дополнения в itfinder/views.py - добавим импорт redirect и обработку POST:
def createProject(request):
form = ProjectForm()
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
form.save()
return redirect('projects')
Теперь данные сохраняются – запись добавлена в список проектов. Реализовать редактирование проектов несложно. Сначала добавим новую функцию в views.py:
def updateProject(request, pk):
project = Project.objects.get(id=pk)
form = ProjectForm(instance=project)
if request.method == 'POST':
form = ProjectForm(request.POST, instance=project)
if form.is_valid():
form.save()
return redirect('projects')
context = {'form': form}
return render(request, 'projects/project_form.html', context)
Параметр instance=project
здесь обеспечивает предзаполнение формы существующими в базе данными:

Теперь сделаем нужный маршрут в urls.py:
path('update-project/<str:pk>', views.updateProject, name="update-project"),
И добавим ссылку на редактирование в шаблон projects.html:
<h4><a href="{% url 'update-project' project.id %}">Редактировать проект</a></h4>
Для удаления проектов (а в дальнейшем – и других объектов) нужно сделать шаблон, запрашивающий подтверждение действий пользователя. Создайте файл delete.html и сохраните в нем код:
{% block content %}
<form action="" method="POST">
{% csrf_token %}
<p>Вы действительно хотите удалить "{{ object }}"?</p>
<a href="{% url 'projects' %}">Отмена</a>
<input type="submit" name="" value="Подтвердить удаление" />
</form>
{% endblock %}
В файл views.py добавьте функцию удаления:
def deleteProject(request, pk):
project = Project.objects.get(id=pk)
if request.method == 'POST':
project.delete()
return redirect('projects')
context = {'object': project}
return render(request, 'projects/delete.html', context)
На этом работа по созданию CRUD закончена, перейдем к дизайну и статическим файлам.
Статические файлы
Создайте папку static в корневой директории проекта. Внутри static создайте 3 папки:
- styles – в ней будут находиться css файлы. Поместите туда main.css.
- js – для скриптов. Положите туда этот скрипт.
- uikit – для стилей фронтенда. Там должны быть все эти файлы.
Чтобы Джанго знал, откуда загружать стили, нужно внести дополнения в файл настроек settings.py:
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
Помимо шаблонов, находящихся в папке projects, нам понадобится набор шаблонов, определяющих внешний вид проекта на, так сказать, глобальном уровне. Для этих шаблонов нужно создать папку templates в корневой директории проекта itfinder. Сейчас в эту папку нужно поместить эти два файла – base.html и navbar.html, позже мы добавим туда еще несколько шаблонов.
Шаблоны в папке templates/projects нужно заменить на эти – они соответствуют готовой версии приложения и содержат ссылки на атрибуты моделей, которые мы разработаем на последующих этапах.
Последнее, что мы сделаем на этом этапе – добавим фильтр проектов по тегам. Для этого в views.py нужно добавить эту функцию:
def projects_by_tag(request, tag_slug):
tag = get_object_or_404(Tag, slug=tag_slug)
projects = Project.objects.filter(tags__in=[tag])
context = {
"projects": projects
}
return render(request, "projects/projects.html", context)
В файл urls.py надо вставить маршрут:
path('tag/<slug:tag_slug>', views.projects_by_tag, name="tag"),
В шаблон projects.html добавить этот код:
<div class="project__tags">
{% for tag in project.tags.all %}
<a href="{% url 'tag' tag.slug %}" class="tag tag--pill tag--main">{{tag}}</a>
{% endfor %}
</div>
А в шаблон single-project.html этот:
<div class="singleProject__toolStack">
{% for tag in project.tags.all %}
<a href="{% url 'tag' tag.slug %}" class="tag tag--pill tag--sub tag--lg">{{tag}}</a>
{% endfor %}
</div>
Запустим сервер – наш проект получил дизайн и обзавелся фильтрацией по тегам, причем фильтр работает как на главной странице, так и на странице отдельного проекта:

Весь код для этого этапа можно взять здесь.
В следующей части мы реализуем добавление изображений для проектов с фронтенда, а также разработаем основную функциональность второго приложения, Users.
Материалы по теме
- 🐍🚀 Django с нуля. Часть 1: пишем многопользовательский блог для клуба любителей задач Python
- 🐍🚀 Django с нуля. Часть 2: регистрация, авторизация, ограничение доступа
- 🐍🚀 Django с нуля. Часть 3: создание профилей, сжатие изображений, CRUD и пагинация
Комментарии