# mysite/views.py from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth import logout from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse_lazy from django.db.models import Avg, Count from django.contrib import messages from .models import Musician, Song, Meloman, Rating, Album, Genre from .forms import MusicianForm, SongForm, RatingForm, RegistrationForm from django.views.generic import TemplateView # Регистрация def register(request): if request.method == 'POST': form = RegistrationForm(request.POST) if form.is_valid(): form.save() messages.success(request, 'Регистрация прошла успешно! Теперь вы можете войти в систему.') return redirect('mysite:login') else: form = RegistrationForm() return render(request, 'mysite/register.html', {'form': form}) # Выход из системы def custom_logout(request): logout(request) messages.success(request, 'Вы успешно вышли из системы') return redirect('mysite:login') # Главная страница со списком песен class SongListView(ListView): model = Song template_name = 'mysite/song_list.html' context_object_name = 'songs' def get_queryset(self): return Song.objects.select_related('album__musician', 'genre').annotate( avg_rating=Avg('rating__score'), ratings_count=Count('rating') ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) search_query = self.request.GET.get('search', '') if search_query: context['songs'] = context['songs'].filter( title__icontains=search_query ) | context['songs'].filter( album__musician__name__icontains=search_query ) context['search_query'] = search_query return context # Список исполнителей class MusicianListView(LoginRequiredMixin, ListView): model = Musician template_name = 'mysite/musician_list.html' context_object_name = 'musicians' paginate_by = 10 def get_queryset(self): return Musician.objects.annotate(albums_count=Count('album')) class MusicianCreateView(LoginRequiredMixin, CreateView): model = Musician form_class = MusicianForm template_name = 'mysite/musician_form.html' success_url = reverse_lazy('mysite:musician_list') def form_valid(self, form): messages.success(self.request, 'Исполнитель успешно добавлен') return super().form_valid(form) class MusicianUpdateView(LoginRequiredMixin, UpdateView): model = Musician form_class = MusicianForm template_name = 'mysite/musician_form.html' success_url = reverse_lazy('mysite:musician_list') def form_valid(self, form): messages.success(self.request, 'Данные исполнителя обновлены') return super().form_valid(form) class MusicianDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView): model = Musician template_name = 'mysite/musician_confirm_delete.html' success_url = reverse_lazy('mysite:musician_list') def test_func(self): return self.request.user.is_superuser def delete(self, request, *args, **kwargs): messages.success(request, 'Исполнитель удален') return super().delete(request, *args, **kwargs) # Список песен для CRUD class SongListDataView(LoginRequiredMixin, ListView): model = Song template_name = 'mysite/song_list_data.html' context_object_name = 'songs' def get_queryset(self): return Song.objects.select_related('album__musician', 'genre').annotate( avg_rating=Avg('rating__score') ) class SongCreateView(LoginRequiredMixin, CreateView): model = Song form_class = SongForm template_name = 'mysite/song_form.html' success_url = reverse_lazy('mysite:song_list_data') def form_valid(self, form): messages.success(self.request, 'Песня успешно добавлена') return super().form_valid(form) class SongUpdateView(LoginRequiredMixin, UpdateView): model = Song form_class = SongForm template_name = 'mysite/song_form.html' success_url = reverse_lazy('mysite:song_list_data') def form_valid(self, form): messages.success(self.request, 'Данные песни обновлены') return super().form_valid(form) class SongDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView): model = Song template_name = 'mysite/song_confirm_delete.html' success_url = reverse_lazy('mysite:song_list_data') def test_func(self): return self.request.user.is_superuser # Список меломанов class MelomanListView(LoginRequiredMixin, ListView): model = Meloman template_name = 'mysite/meloman_list.html' context_object_name = 'melomans' def get_queryset(self): return Meloman.objects.annotate( ratings_count=Count('rating'), avg_score=Avg('rating__score') ) def dispatch(self, request, *args, **kwargs): if not request.user.is_superuser: return redirect('mysite:song_list') return super().dispatch(request, *args, **kwargs) # Профиль меломана class MelomanProfileView(LoginRequiredMixin, DetailView): model = Meloman template_name = 'mysite/profile.html' context_object_name = 'meloman' def get_object(self): try: return Meloman.objects.get(user=self.request.user) except Meloman.DoesNotExist: return None def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) meloman = self.get_object() if meloman: context['total_ratings'] = meloman.rating_set.count() context['avg_user_rating'] = meloman.rating_set.aggregate(Avg('score'))['score__avg'] context['favorite_genres'] = meloman.preference_set.select_related('genre').all() context['age'] = meloman.age context['recent_ratings'] = meloman.rating_set.select_related('song').order_by('-rating_date')[:5] return context # Оценка песни def rate_song(request, song_id): if not request.user.is_authenticated: return redirect('mysite:login') song = get_object_or_404(Song, pk=song_id) try: meloman = Meloman.objects.get(user=request.user) except Meloman.DoesNotExist: messages.error(request, 'У вас нет профиля меломана. Обратитесь к администратору.') return redirect('mysite:song_list') rating, created = Rating.objects.get_or_create( meloman=meloman, song=song, defaults={'score': 5} ) if request.method == 'POST': form = RatingForm(request.POST, instance=rating) if form.is_valid(): form.save() messages.success(request, f'Оценка для "{song.title}" сохранена!') return redirect('mysite:song_list') else: form = RatingForm(instance=rating) return render(request, 'mysite/rate_song.html', {'form': form, 'song': song}) from django.db import connection class SongDetailsView(ListView): """Использование представления song_details_view""" template_name = 'mysite/song_details.html' context_object_name = 'songs' def get_queryset(self): with connection.cursor() as cursor: cursor.execute(""" SELECT song_id, title, musician_name, album_name, genre_name, duration_sec, avg_rating, ratings_count FROM song_details_view ORDER BY avg_rating DESC NULLS LAST """) columns = [col[0] for col in cursor.description] return [dict(zip(columns, row)) for row in cursor.fetchall()] class RecommendationsView(LoginRequiredMixin, TemplateView): """Использование функции recommend_songs""" template_name = 'mysite/recommendations.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) try: meloman = Meloman.objects.get(user=self.request.user) meloman_id = meloman.meloman_id except Meloman.DoesNotExist: context['recommendations'] = [] context['error'] = 'Профиль меломана не найден' return context with connection.cursor() as cursor: cursor.execute(""" SELECT * FROM recommend_songs(%s, %s) """, [meloman_id, 10]) columns = [col[0] for col in cursor.description] recommendations = [dict(zip(columns, row)) for row in cursor.fetchall()] context['recommendations'] = recommendations return context