Share This
Связаться со мной
Крути в низ
Categories
//Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

В этой части: добавление обложек проектов с фронтенда, создание системы авторизации, разработка основной функциональности приложения «Пользователи» и связь проектов с профилями.

sozdaem rekrutingovyj portal analog hhru na django chast 2 b2a3fcb - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Первая часть 🐍🚀 Создаем рекрутинговый портал на Django: часть 1

Третий этап

Основная часть работы над приложением «Проекты» была выполнена на предыдущем этапе – осталось реализовать добавление изображений. Для этого нужно внести дополнения в модель Projects:

         image = models.ImageField(null=True, blank=True, default="project_images/default.jpg", upload_to='project_images')     

А затем выполнить миграции:

         python manage.py makemigrations python manage.py migrate      

По умолчанию Джанго будет сохранять изображения прямо в корневую директорию проекта, а искать – в папке static. Гораздо удобнее завести для изображений отдельную папку media в корне проекта (а не внутри static). Создайте директорию media, внутри нее папку project_images и поместите в нее файл default.jpg.

Чтобы дать Джанго знать, куда сохранять изображения, сделаем нужные настройки в settings.py:

         MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'      

В файл urls.py добавим импорт:

         from django.conf.urls.static import static     

И маршруты к нужным папкам:

         urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)      

Осталось добавить ссылки на изображения в шаблон projects.html:

         <img class="project__thumbnail" src="{{ project.image.url }}" alt="скриншот проекта" />     

И в single-project.html:

         <img class="singleProject__preview" src="{{ project.image.url }}" alt="скриншот проекта" />     

sozdaem rekrutingovyj portal analog hhru na django chast 2 01df15d - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Изображение на странице проекта

Пока что добавлять изображения в карточки проектов можно только в панели администрирования. Чтобы дать пользователям возможность добавлять изображения на стороне фронтенда, сделаем новый шаблон project_form.html:

         {% extends 'base.html' %} {% block content %}   <main class="formPage my-xl">  <div class="content-box">      <div class="formWrapper">          <a class="backButton" href="#"><i class="im im-angle-left"></i></a>           <br>           <form class="form" method="POST" enctype="multipart/form-data">            {% csrf_token %}            {% for field in form %}            <div class="form__field">             <label for="formInput#text">{{ field.label }}</label>                  {{ field }}            </div>            {% endfor %}            <div class="form__field">             {% for tag in project.tags.all %}              <div class="project-tag tag tag--pill tag--main" data-tag="{{ tag.id }}"                data-project="{{ project.id }}">{{ tag.name }} &#215;</div>             {% endfor %}             </div>             <div class="form__field">              <label for="formInput#text">Теги</label>              <textarea class="input" name="newtags" placeholder="Добавьте собственные теги, если их нет в списке"></textarea>              </div>              <input class="btn btn--sub btn--lg  my-md" type="submit" value="Сохранить" />           </form>     	 </div>     </div> </main> {% endblock %}      

Кроме того, внесем дополнения в forms.py:

         from django.forms import ModelForm from django import forms from .models import Project   class ProjectForm(ModelForm):     class Meta:     model = Project     fields = ['title', 'slug', 'image', 'tags', 'description', 'demo_link', 'source_link']     labels = {          'title': 'Название проекта',          'slug': 'Слаг',          'image':'Скриншот проекта',          'tags':'Теги',          'description':'Описание проекта',          'demo_link':'Демо-версия',          'source_link':'Исходный код на GitHub'          }        widgets = {          'tags': forms.CheckboxSelectMultiple(),     	}        def __init__(self, *args, **kwargs):          super(ProjectForm, self).__init__(*args, **kwargs)          for name, field in self.fields.items():              field.widget.attrs.update({'class': 'input'})       

Для сохранения изображений с фронтенда добавим FILES в функции createProject и updateProject:

         def createProject(request):      form = ProjectForm()      if request.method == 'POST':          form = ProjectForm(request.POST, request.FILES)          if form.is_valid():              form.save()              return redirect('projects')      context = {'form': form}      return render(request, 'projects/project_form.html', context) def updateProject(request, pk):      project = Project.objects.get(id=pk)      form = ProjectForm(instance=project)      if request.method == 'POST':          form = ProjectForm(request.POST, request.FILES, instance=project)          if form.is_valid():              form.save()              return redirect('projects')      context = {'form': form}      return render(request, 'projects/project_form.html', context)      

Создать проект можно по прежней ссылке – http://localhost:8000/create-project/, однако в навигационную панель мы эту ссылку добавлять не станем – позже она будет доступна в профиле пользователя.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу

Приложение Users – «Пользователи»

Начнем разработку секции «Пользователи» с создания нового приложения:

         python manage.py startapp users     

Как и в случае с projects, приложение нужно зарегистрировать в INSTALLED_APPS (settings.py):

         'users.apps.UsersConfig'     

Для вывода профилей нам понадобятся два шаблона – profiles.html и user-profile.html, поместите их в папку users/templates/users.

Теперь создадим нужные функции представления – для вывода всех профилей, просмотра отдельного профиля и фильтрации профилей по скиллам. Сохраните этот код в файле users/views.py:

         from django.shortcuts import render, get_object_or_404 from .models import Profile, Skill   def profiles(request):     profiles = Profile.objects.all()     context = {'profiles': profiles}     return render(request, 'users/profiles.html', context)     def userProfile(request, pk):     profile = Profile.objects.get(id=pk)     main_skills = profile.skills.all()[:2]     extra_skills = profile.skills.all()[2:]     context = {'profile': profile, 'main_skills': main_skills,            	"extra_skills": extra_skills}     return render(request, 'users/user-profile.html', context)   def profiles_by_skill(request, skill_slug):     skill = get_object_or_404(Skill, slug=skill_slug)     profiles = Profile.objects.filter(skills__in=[skill])     context = {     	"profiles": profiles 	}     return render(request, "users/profiles.html", context)      

Создайте файл users/urls.py и сохраните в нем эти маршруты:

         from django.urls import path from . import views   urlpatterns = [     path('', views.profiles, name="profiles"),     path('profile/<str:pk>/', views.userProfile, name="user-profile"),     path('skill/<slug:skill_slug>', views.profiles_by_skill, name="skill"), ]      

Внесите изменения в urlpatterns в главном urls.py в корневой директории проекта itfinder:

         path('projects/', include('projects.urls')), path('', include('users.urls')),      

Измените ссылку на главную страницу в шаблоне navbar.html – вставьте {% url 'profiles' %}.

И, наконец, сохраните нужные модели в users/models.py:

         from django.db import models from django.contrib.auth.models import User import uuid   class Skill(models.Model):     name = models.CharField(max_length=50, blank=True, null=True)     slug = models.SlugField()     description = models.TextField(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 str(self.name)     class Profile(models.Model):     user = models.OneToOneField(         User, on_delete=models.CASCADE, null=True, blank=True)     name = models.CharField(max_length=50, blank=True, null=True)     email = models.EmailField(max_length=50, blank=True, null=True)     username = models.CharField(max_length=50, blank=True, null=True)     city = models.CharField(max_length=50, blank=True, null=True)     intro = models.CharField(max_length=200, blank=True, null=True)     bio = models.TextField(blank=True, null=True)     image = models.ImageField(         null=True, blank=True, upload_to='profile_images', default="profile_images/default.jpg")     skills = models.ManyToManyField(Skill, blank=True)     github = models.CharField(max_length=100, blank=True, null=True)     twitter = models.CharField(max_length=100, blank=True, null=True)     linkedin = models.CharField(max_length=100, blank=True, null=True)     youtube = models.CharField(max_length=100, blank=True, null=True)     website = models.CharField(max_length=100, blank=True, null=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 str(self.username)       class Meta:         ordering = ['created']      

Теперь создайте и примените миграции:

         python manage.py makemigrations python manage.py migrate      

Запустите сервер – можно создавать профили в админ-панели. На главной странице теперь выводятся профили разработчиков:

sozdaem rekrutingovyj portal analog hhru na django chast 2 a1cc4e8 - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Профили на главной странице ITfinder

Карточки в разделе «Проекты» пока не связаны с их авторами – мы займемся этим на следующем этапе:

sozdaem rekrutingovyj portal analog hhru na django chast 2 f85220a - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Проекты

Четвертый этап

Для связи проектов с профилями разработчиков добавим импорт модели профиля в projects/models.pyfrom users.models import Profile и внесем дополнения в модель проекта:

         owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.CASCADE)     

Подготовьте и выполните миграции:

         python manage.py makemigrations python manage.py migrate      

В панели управления выберите разработчиков-авторов для проектов, а в шаблонах projects/projects.html и projects/single-project.html вставьте ссылку на автора:

         {% url 'user-profile' project.owner.id %}     

Запустите сервер и перейдите на страницу «Проекты» – у каждого проекта теперь есть автор, и в профилях разработчиков отображаются их проекты:

sozdaem rekrutingovyj portal analog hhru na django chast 2 ac3eceb - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Проект разработчика в профиле

Сигналы

Сигналы обеспечивают «прослушивание» действий пользователей и запуск нужных событий: к примеру, сигналы могут триггерить вспомогательные функции, которые нам потребуются в процессе создания, удаления и обновления учетных записей.

Создайте файл users/signals.py и сохраните в нем этот код, а в файл users/apps.py внесите это дополнение:

         def ready(self):     import users.signals     

Теперь можно перейти к созданию всей нужной функциональности для учетных записей.

Регистрация, аутентификация, права доступа

Аутентификация подтверждает личность пользователя, а система авторизации предоставляет (или ограничивает) доступ к определенным функциям и разделам сайта, в зависимости от того зарегистрирован ли пользователь или нет.

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

  • login_register.html
  • account.html
  • profile_form.html
  • skill_form.html

Добавьте в users/urls.py маршруты:

         path('login/', views.loginUser, name="login"), path('logout/', views.logoutUser, name="logout"), path('register/', views.registerUser, name="register"),   path('account/', views.userAccount, name="account"), path('edit-account/', views.editAccount, name="edit-account"), path('create-skill/', views.createSkill, name="create-skill"), path('update-skill/<slug:skill_slug>/', views.updateSkill, name="update-skill"), path('delete-skill/<slug:skill_slug>/', views.deleteSkill, name="delete-skill"),      

В шаблон navbar.html добавьте ссылки на аккаунт, вход/регистрацию, выход:

         {% url 'account' %} {% url 'login' %} {% url 'logout' %}      

Доступ для авторизованных пользователей

Декоратор @login_required(login_url='login') обеспечивает доступ к определенным функциям только для зарегистрированных и авторизованных пользователей. Сохраните эти представления в файле users/views.py:

         @login_required(login_url='login') def userAccount(request):     profile = request.user.profile       skills = profile.skills.all()     projects = profile.project_set.all()       context = {'profile': profile, 'skills': skills, 'projects': projects}     return render(request, 'users/account.html', context)     @login_required(login_url='login') def editAccount(request):     profile = request.user.profile     form = ProfileForm(instance=profile)       if request.method == 'POST':         form = ProfileForm(request.POST, request.FILES, instance=profile)         if form.is_valid():             form.save()               return redirect('account')       context = {'form': form}     return render(request, 'users/profile_form.html', context)     @login_required(login_url='login') def createSkill(request):     profile = request.user.profile     form = SkillForm()       if request.method == 'POST':         form = SkillForm(request.POST)         if form.is_valid():             skill = form.save(commit=False)             skill_slug = request.POST.get('slug')             skill_description = request.POST.get('description')             profile.skills.get_or_create(name=skill, slug=skill_slug, description=skill_description)             messages.success(request, 'Навык добавлен')             return redirect('account')       context = {'form': form}     return render(request, 'users/skill_form.html', context)     @login_required(login_url='login') def updateSkill(request, skill_slug):     profile = request.user.profile     skill = profile.skills.get(slug=skill_slug)     form = SkillForm(instance=skill)       if request.method == 'POST':         form = SkillForm(request.POST, instance=skill)         if form.is_valid():             form.save()             messages.success(request, 'Навык успешно обновлен')             return redirect('account')       context = {'form': form}     return render(request, 'users/skill_form.html', context)     @login_required(login_url='login') def deleteSkill(request, skill_slug):     profile = request.user.profile     skill = profile.skills.get(slug=skill_slug)     if request.method == 'POST':         skill.delete()         messages.success(request, 'Навык успешно удален')         return redirect('account')       context = {'object': skill}     return render(request, 'delete_template.html', context)      

Помимо функций userAccount, editAccount, createSkill, updateSkill, deleteSkill мы добавим декоратор к функциям в файле views.py в приложении «Проекты» – поскольку добавлять, редактировать и удалять проекты могут только авторизованные пользователи. Функции createSkill, updateSkill, deleteSkill обеспечивают добавление, редактирование и удаление пользователями скиллов в своих профилях:

sozdaem rekrutingovyj portal analog hhru na django chast 2 64becf2 - Создаем рекрутинговый портал, аналог hh.ru на Django: часть 2

Пользователи могут редактировать любые данные

Удаление скиллов и проектов обрабатывает шаблон delete_template.html – его нужно поместить в папку с глобальными шаблонами templates. Кроме того, создайте новый файл users/forms.py, содержащий нужные формы.

Чтобы включить юзернеймы разработчиков в URL, в шаблонах templates/users мы заменим project.owner.id на project.owner, a маршрут в urls.py на этот:

         path('profile/<str:username>/', views.userProfile, name="user-profile"),     

После чего добавим ссылку на аккаунт разработчика в форму создания нового проекта:

         {% url 'account' %}     

Автоматическая генерация слагов

Если пользователь решит добавить к своему проекту теги, которых еще нет в базе, для них нужно будет сгенерировать слаги. Для этого добавьте импорт в projects/models.py:

         from django.utils.text import slugify     

И эту функцию в класс Tag:

             def save(self, *args, **kwargs):         value = self.name         self.slug = slugify(value, allow_unicode=True)         super().save(*args, **kwargs)       

Весь код и тестовый контент для этого этапа – в репозитории ITfinder.

***

Материалы по теме

  • 🐍🥤Flask за час. Часть 1: создаем адаптивный сайт для GitHub Pages
  • 🐍📚 Создаем аналог LiveLib.ru на Flask. Часть 1: основы работы с SQLAlchemy
  • 🐍📚 Создаем аналог LiveLib.ru на Flask. Часть 2: CRUD, IntegrityError и валидация WTForms

  • 0 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close