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 для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

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