В заключительной части: создание мессенджера, реализация поиска по профилям и проектам, отзывы и пагинация. Первая часть 🐍🚀 Создаем рекрутинговый портал на Django: часть 1 Вторая часть 🐍🚀 Создаем рекрутинговый портал на Django: часть 2 Пятый этап Зарегистрированные пользователи сайта ITfinder должны иметь возможность обмениваться сообщениями и оставлять отзывы о проектах. И то, и другое реализовать на Django несложно. Мессенджер Начнем работу с создания модели Message – сохраните этот код в users/models.py: class Message(models.Model): sender = models.ForeignKey( Profile, on_delete=models.SET_NULL, null=True, blank=True) recipient = models.ForeignKey( Profile, on_delete=models.SET_NULL, null=True, blank=True, related_name="messages") name = models.CharField(max_length=200, null=True, blank=True) email = models.EmailField(max_length=200, null=True, blank=True) subject = models.CharField(max_length=200, null=True, blank=True) body = models.TextField() is_read = models.BooleanField(default=False, 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 self.subject class Meta: ordering = ['is_read', '-created'] Подготовьте и примените миграции: python manage.py makemigrations python manage.py migrate После этого добавьте импорт Message и новый класс в users/form.py: class MessageForm(ModelForm): class Meta: model = Message fields = ['name', 'email', 'subject', 'body'] def __init__(self, *args, **kwargs): super(MessageForm, self).__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs.update({'class': 'input'}) Шаблоны, которые понадобятся для мессенджера: inbox.html message.html message_form.html Сохраните эти шаблоны в templates/users. Еще мы добавим ссылку на входящие в шаблоне navbar.html – {% url 'inbox' %}. Мессенджер на Django Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу Отзывы о проектах В первой части туториала мы уже частично реализовали функциональность для отзывов о проектах. Теперь нам нужно связать отзывы с пользователями. Для этого мы внесем дополнения в модель Project: @property def reviewers(self): queryset = self.review_set.all().values_list('owner__id', flat=True) return queryset @property def getVoteCount(self): reviews = self.review_set.all() upVotes = reviews.filter(value='up').count() totalVotes = reviews.count() ratio = (upVotes / totalVotes) * 100 self.vote_total = totalVotes self.vote_ratio = ratio self.save() Дополним класс Review: class Review(models.Model): VOTE_TYPE = ( ('up', 'Положительная оценка'), ('down', 'Отрицательная оценка'), ) owner = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True) project = models.ForeignKey(Project, on_delete=models.CASCADE) body = 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) class Meta: unique_together = [['owner', 'project']] def __str__(self): return self.value В шаблоне single-projects.html изменим ссылки на авторов отзывов: {% url 'user-profile' review.owner %}, после чего добавим форму отзыва в projects/forms.py: class ReviewForm(ModelForm): class Meta: model = Review fields = ['value', 'body'] labels = { 'value': 'Оцените проект', 'body': 'Добавьте комментарий' } def __init__(self, *args, **kwargs): super(ReviewForm, self).__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs.update({'class': 'input'}) Осталось внести небольшие изменения в представление проекта в файле projects/views.py. Добавим import ReviewForm и код: def project(request, project_slug): project = Project.objects.get(slug=project_slug) tags = project.tags.all() form = ReviewForm() if request.method == 'POST': form = ReviewForm(request.POST) review = form.save(commit=False) review.project = project review.owner = request.user.profile review.save() project.getVoteCount messages.success(request, 'Ваш отзыв был добавлен!') return redirect('project', project_slug=project.slug) return render(request, 'projects/single-project.html', {'project': project, 'form': form}) Готово, теперь на сайте есть система отзывов: Система комментариев на Django Шестой этап На заключительном этапе мы сделаем пагинацию профилей и проектов, а затем реализуем систему поиска. Пагинация Сначала сделаем пагинацию для вывода проектов. Создайте файл projects/utils.py, а в файл projects/views.py добавьте импорт: from django.core import paginator from .utils import paginateProjects В конец шаблона projects.html добавьте: {% include 'pagination.html' with queryset=projects custom_range=custom_range %} После этого в папку с глобальными шаблонами положите файл pagination.html. Запустите сервер и проверьте: проекты теперь выводятся постранично. Таким же образом сделаем пагинацию для постраничного вывода профилей в приложении Users: создадим файл utils.py; добавим изменения в шаблон profiles.html; внесем дополнения в users/views.py. Готово – теперь профили выводятся по 6 штук на странице: Пагинация Поиск Мы реализуем поиск по проектам и профилям с помощью модуля Q. Сначала добавим импорт from django.db.models import Q и эту функцию в projects/utils.py: def searchProjects(request): search_query = '' if request.GET.get('search_query'): search_query = request.GET.get('search_query') tags = Tag.objects.filter(name__icontains=search_query) projects = Project.objects.distinct().filter( Q(title__icontains=search_query) | Q(description__icontains=search_query) | Q(owner__name__icontains=search_query) | Q(tags__in=tags) ) return projects, search_query Использование модуля Q значительно изменит представление для вывода проектов: def projects(request): projects, search_query = searchProjects(request) custom_range, projects = paginateProjects(request, projects, 6) context = {'projects': projects, 'search_query': search_query, 'custom_range': custom_range} return render(request, 'projects/projects.html', context) Вызов Q в шаблоне projects.html производит {{ search_query }}. Все готово – поиск по проектам работает: Результаты поиска по запросу «магазин» То же самое сделаем для поиска по профилям. Добавим функцию поиска в users/utils.py: def searchProfiles(request): search_query = '' if request.GET.get('search_query'): search_query = request.GET.get('search_query') skills = Skill.objects.filter(name__icontains=search_query) profiles = Profile.objects.distinct().filter( Q(name__icontains=search_query) | Q(short_intro__icontains=search_query) | Q(skill__in=skills) ) return profiles, search_query Изменим представление для вывода профилей в users/views.py: def profiles(request): profiles, search_query = searchProfiles(request) custom_range, profiles = paginateProfiles(request, profiles, 6) context = {'profiles': profiles, 'search_query': search_query, 'custom_range': custom_range} return render(request, 'users/profiles.html', context) И добавим {{ search_query }} в profiles.html. Готово – поиск по профилям работает: Результаты поиска по запросу «Python» На этом разработка сайта завершена. Код готового проекта можно взять в репозитории ITfinder. *** Материалы по теме 🐍🚀 Django с нуля. Часть 1: пишем многопользовательский блог для клуба любителей задач Python 🐍🚀 Django с нуля. Часть 2: регистрация, авторизация, ограничение доступа 🐍🚀 Django с нуля. Часть 3: создание профилей, сжатие изображений, CRUD и пагинация
Первая часть 🐍🚀 Создаем рекрутинговый портал на Django: часть 1 Вторая часть 🐍🚀 Создаем рекрутинговый портал на Django: часть 2
Зарегистрированные пользователи сайта ITfinder должны иметь возможность обмениваться сообщениями и оставлять отзывы о проектах. И то, и другое реализовать на Django несложно.
Начнем работу с создания модели Message – сохраните этот код в users/models.py:
Message
class Message(models.Model): sender = models.ForeignKey( Profile, on_delete=models.SET_NULL, null=True, blank=True) recipient = models.ForeignKey( Profile, on_delete=models.SET_NULL, null=True, blank=True, related_name="messages") name = models.CharField(max_length=200, null=True, blank=True) email = models.EmailField(max_length=200, null=True, blank=True) subject = models.CharField(max_length=200, null=True, blank=True) body = models.TextField() is_read = models.BooleanField(default=False, 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 self.subject class Meta: ordering = ['is_read', '-created']
Подготовьте и примените миграции:
python manage.py makemigrations python manage.py migrate
После этого добавьте импорт Message и новый класс в users/form.py:
class MessageForm(ModelForm): class Meta: model = Message fields = ['name', 'email', 'subject', 'body'] def __init__(self, *args, **kwargs): super(MessageForm, self).__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs.update({'class': 'input'})
Шаблоны, которые понадобятся для мессенджера:
Сохраните эти шаблоны в templates/users. Еще мы добавим ссылку на входящие в шаблоне navbar.html – {% url 'inbox' %}.
{% url 'inbox' %}
Мессенджер на Django Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу
В первой части туториала мы уже частично реализовали функциональность для отзывов о проектах. Теперь нам нужно связать отзывы с пользователями. Для этого мы внесем дополнения в модель Project:
Project
@property def reviewers(self): queryset = self.review_set.all().values_list('owner__id', flat=True) return queryset @property def getVoteCount(self): reviews = self.review_set.all() upVotes = reviews.filter(value='up').count() totalVotes = reviews.count() ratio = (upVotes / totalVotes) * 100 self.vote_total = totalVotes self.vote_ratio = ratio self.save()
Дополним класс Review:
Review
class Review(models.Model): VOTE_TYPE = ( ('up', 'Положительная оценка'), ('down', 'Отрицательная оценка'), ) owner = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True) project = models.ForeignKey(Project, on_delete=models.CASCADE) body = 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) class Meta: unique_together = [['owner', 'project']] def __str__(self): return self.value
В шаблоне single-projects.html изменим ссылки на авторов отзывов: {% url 'user-profile' review.owner %}, после чего добавим форму отзыва в projects/forms.py:
{% url 'user-profile' review.owner %}
class ReviewForm(ModelForm): class Meta: model = Review fields = ['value', 'body'] labels = { 'value': 'Оцените проект', 'body': 'Добавьте комментарий' } def __init__(self, *args, **kwargs): super(ReviewForm, self).__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs.update({'class': 'input'})
Осталось внести небольшие изменения в представление проекта в файле projects/views.py. Добавим import ReviewForm и код:
import ReviewForm
def project(request, project_slug): project = Project.objects.get(slug=project_slug) tags = project.tags.all() form = ReviewForm() if request.method == 'POST': form = ReviewForm(request.POST) review = form.save(commit=False) review.project = project review.owner = request.user.profile review.save() project.getVoteCount messages.success(request, 'Ваш отзыв был добавлен!') return redirect('project', project_slug=project.slug) return render(request, 'projects/single-project.html', {'project': project, 'form': form})
Готово, теперь на сайте есть система отзывов:
Система комментариев на Django
На заключительном этапе мы сделаем пагинацию профилей и проектов, а затем реализуем систему поиска.
Сначала сделаем пагинацию для вывода проектов. Создайте файл projects/utils.py, а в файл projects/views.py добавьте импорт:
from django.core import paginator from .utils import paginateProjects
В конец шаблона projects.html добавьте:
{% include 'pagination.html' with queryset=projects custom_range=custom_range %}
После этого в папку с глобальными шаблонами положите файл pagination.html.
Запустите сервер и проверьте: проекты теперь выводятся постранично.
Таким же образом сделаем пагинацию для постраничного вывода профилей в приложении Users:
Готово – теперь профили выводятся по 6 штук на странице:
Пагинация
Мы реализуем поиск по проектам и профилям с помощью модуля Q. Сначала добавим импорт from django.db.models import Q и эту функцию в projects/utils.py:
from django.db.models import Q
def searchProjects(request): search_query = '' if request.GET.get('search_query'): search_query = request.GET.get('search_query') tags = Tag.objects.filter(name__icontains=search_query) projects = Project.objects.distinct().filter( Q(title__icontains=search_query) | Q(description__icontains=search_query) | Q(owner__name__icontains=search_query) | Q(tags__in=tags) ) return projects, search_query
Использование модуля Q значительно изменит представление для вывода проектов:
def projects(request): projects, search_query = searchProjects(request) custom_range, projects = paginateProjects(request, projects, 6) context = {'projects': projects, 'search_query': search_query, 'custom_range': custom_range} return render(request, 'projects/projects.html', context)
Вызов Q в шаблоне projects.html производит {{ search_query }}. Все готово – поиск по проектам работает:
{{ search_query }}
Результаты поиска по запросу «магазин»
То же самое сделаем для поиска по профилям. Добавим функцию поиска в users/utils.py:
def searchProfiles(request): search_query = '' if request.GET.get('search_query'): search_query = request.GET.get('search_query') skills = Skill.objects.filter(name__icontains=search_query) profiles = Profile.objects.distinct().filter( Q(name__icontains=search_query) | Q(short_intro__icontains=search_query) | Q(skill__in=skills) ) return profiles, search_query
Изменим представление для вывода профилей в users/views.py:
def profiles(request): profiles, search_query = searchProfiles(request) custom_range, profiles = paginateProfiles(request, profiles, 6) context = {'profiles': profiles, 'search_query': search_query, 'custom_range': custom_range} return render(request, 'users/profiles.html', context)
И добавим {{ search_query }} в profiles.html. Готово – поиск по профилям работает:
Результаты поиска по запросу «Python»
На этом разработка сайта завершена. Код готового проекта можно взять в репозитории ITfinder.
***
Ваш адрес email не будет опубликован. Обязательные поля помечены *
Сохранить моё имя, email и адрес сайта в этом браузере для последующих моих комментариев.
Δ
Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.