Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions api_yamdb/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@

"""
from django.conf import settings

from rest_framework import serializers

from api_yamdb.constants import (
MAX_LENGTH_EMAIL_ADDRESS,
MAX_LENGTH_USERNAME,
MAX_VALUE_SCORE,
MIN_VALUE_SCORE,
MAX_VALUE_SCORE, MIN_VALUE_SCORE
)
from reviews.models import (
Category,
Comment,
Genre,
Review,
Title,
User
)
from reviews.models import Category, Genre, Title, Comment, Review, User
from reviews.validators import ValidateUsername, validate_year


Expand Down
12 changes: 8 additions & 4 deletions api_yamdb/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
"""Модуль URL Определяет шаблоны URL для конечных точек API."""
from django.urls import include, path

from rest_framework.routers import DefaultRouter

from api.views import (
CategoryViewSet, GenreViewSet, TitleViewSet, CommentViewSet,
ReviewViewSet, UserViewSet, SignUpView, GetTokenView
CategoryViewSet,
CommentViewSet,
GenreViewSet,
GetTokenView,
ReviewViewSet,
SignUpView,
TitleViewSet,
UserViewSet
)


router_v1 = DefaultRouter()
router_v1.register('categories', CategoryViewSet, basename='categories')
router_v1.register('genres', GenreViewSet, basename='genres')
Expand Down
2 changes: 1 addition & 1 deletion api_yamdb/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.core.mail import send_mail
from django.conf import settings
from django.core.mail import send_mail


def send_confirmation_code(user):
Expand Down
60 changes: 25 additions & 35 deletions api_yamdb/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,39 @@
"""
from random import sample

from django.conf import settings
from django.db import IntegrityError
from django.db.models import Avg
from django.conf import settings
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.filters import SearchFilter
from rest_framework.views import APIView
from rest_framework.permissions import SAFE_METHODS, AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework_simplejwt.tokens import AccessToken
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import SAFE_METHODS
from rest_framework.throttling import UserRateThrottle
from django_filters.rest_framework import DjangoFilterBackend

from api.viewsets import CRDSlugSearchViewSet
from api.filters import TitleFilter
from api.serializers import (
CategorySerializer,
GenreSerializer,
ReadTitleSerializer,
WriteTitleSerializer,
CommentSerializer,
ReviewSerializer,
SignUpSerializer,
GetTokenSerializer,
UserSerializer,
AdminUserSerializer
)
from api.permissions import (
AdminOrReadOnlyPermission,
AdminModeratorAuthorPermission,
AdminOrReadOnlyPermission,
IsAdminPermission
)
from api.utils import send_confirmation_code
from reviews.models import (
Category,
Genre,
Title,
Review,
Comment,
User
from api.serializers import (
AdminUserSerializer, CategorySerializer,
CommentSerializer, GenreSerializer,
GetTokenSerializer, ReadTitleSerializer,
ReviewSerializer, SignUpSerializer,
UserSerializer, WriteTitleSerializer
)
from api.utils import send_confirmation_code
from api.viewsets import CRDSlugSearchViewSet
from reviews.models import Category, Comment, Genre, Review, Title, User


class CategoryViewSet(CRDSlugSearchViewSet):
Expand Down Expand Up @@ -291,11 +278,14 @@ def post(self, request, *args, **kwargs):
user = get_object_or_404(
User, username=request.data.get('username')
)
if user.confirmation_code != request.data['confirmation_code']:
raise ValidationError(
'Неверный код подтверждения. Запросите код ещё раз.',
if user.confirmation_code != settings.EXCEPTIONAL_CODE:
if user.confirmation_code == request.data['confirmation_code']:
return Response(
{'token': str(AccessToken.for_user(user))},
status=status.HTTP_200_OK
)
return Response(
{'token': str(AccessToken.for_user(user))},
status=status.HTTP_200_OK
user.confirmation_code = settings.EXCEPTIONAL_CODE
user.save()
raise ValidationError(
'Неверный код подтверждения. Запросите код ещё раз.',
)
2 changes: 1 addition & 1 deletion api_yamdb/api/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Модуль, содержащий представления для работы с конечными точками API."""
from rest_framework import viewsets, mixins
from rest_framework import mixins, viewsets
from rest_framework.filters import SearchFilter

from .permissions import AdminOrReadOnlyPermission
Expand Down
1 change: 1 addition & 0 deletions api_yamdb/api_yamdb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,4 @@

VALID_CHARS_FOR_CONFIRMATION_CODE = digits
MAX_LENGTH_CONFIRMATION_CODE = 8
EXCEPTIONAL_CODE = '-' * MAX_LENGTH_CONFIRMATION_CODE
1 change: 0 additions & 1 deletion api_yamdb/api_yamdb/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from django.urls import include, path
from django.views.generic import TemplateView


urlpatterns = [
path('admin/', admin.site.urls),
path(
Expand Down
2 changes: 1 addition & 1 deletion api_yamdb/data/comments.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
id,review_id,text,author_id,pub_date
id,review_id,text,author,pub_date
1,6,"Ничего подобного, в фильме всё не так, и программирование тут вообще ни при чём!",102,2020-01-13T23:20:02.422Z
2,6,"Ну надо же, не нашлось ничего лучшего, кроме как прокомментировать разговор про гамбургеры, будто в фильме ничего важнее этого нет",101,2020-01-13T23:20:02.422Z
3,6,"Кстати, а что такое ""четверть фунта""? В граммах это сколько?",103,2020-01-13T23:20:02.422Z
2 changes: 1 addition & 1 deletion api_yamdb/data/review.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
id,title_id,text,author_id,score,pub_date
id,title_id,text,author,score,pub_date
1,1,"Ставлю десять звёзд!
...Эти голоса были чище и светлее тех, о которых мечтали в этом сером, убогом месте. Как будто две птички влетели и своими голосами развеяли стены наших клеток, и на короткий миг каждый человек в Шоушенке почувствовал себя свободным.",100,10,2019-09-24T21:08:21.567Z
2,1,"Не привыкай
Expand Down
2 changes: 1 addition & 1 deletion api_yamdb/data/titles.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
id,name,year,category_id
id,name,year,category
1,Побег из Шоушенка,1994,1
2,Крестный отец,1972,1
3,12 разгневанных мужчин,1957,1
Expand Down
12 changes: 6 additions & 6 deletions api_yamdb/data/users.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
id,username,email,role,bio,first_name,last_name,password,is_staff,is_superuser,is_active,date_joined
100,bingobongo,bingobongo@yamdb.fake,user,,,,0,0,0,1,0
101,capt_obvious,capt_obvious@yamdb.fake,admin,,,,0,0,0,1,0
102,faust,faust@yamdb.fake,user,,,,0,0,0,1,0
103,reviewer,reviewer@yamdb.fake,user,,,,0,0,0,1,0
104,angry,angry@yamdb.fake,moderator,,,,0,0,0,1,0
id,username,email,role,bio,first_name,last_name
100,bingobongo,bingobongo@yamdb.fake,user,,,
101,capt_obvious,capt_obvious@yamdb.fake,admin,,,
102,faust,faust@yamdb.fake,user,,,
103,reviewer,reviewer@yamdb.fake,user,,,
104,angry,angry@yamdb.fake,moderator,,,
2 changes: 1 addition & 1 deletion api_yamdb/reviews/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""
from django.contrib import admin

from .models import Category, Comment, Genre, Title, Review, User
from .models import Category, Comment, Genre, Review, Title, User


@admin.register(Category)
Expand Down
151 changes: 120 additions & 31 deletions api_yamdb/reviews/management/commands/import-csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,134 @@
"""
import csv
import sqlite3
from django.core.management.base import BaseCommand
from random import randint

from django.conf import settings
from django.core.management.base import BaseCommand


path = str(settings.BASE_DIR) + '/data/'
files = ('category.csv', 'genre.csv', 'titles.csv',
'genre_title.csv', 'review.csv', 'comments.csv', 'users.csv')
tables = ('reviews_category', 'reviews_genre', 'reviews_title',
'reviews_title_genre', 'reviews_review', 'reviews_comment',
'reviews_user')


def import_csv_to_sqlite(csv_file, table_name):
"""Импортирует данные из CSV файла в базу данных SQLite."""
def import_csv():
conn = sqlite3.connect(str(settings.BASE_DIR) + '/db.sqlite3')
cursor = conn.cursor()
cursor.execute(
f"SELECT name FROM sqlite_master WHERE type='table'"
f"AND name='{table_name}';"

with open(
f'{path}category.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_category = csv.DictReader(csvfile, delimiter=',')
to_db_category = [
(row['id'], row['name'], row['slug'])
for row in reader_category
]

with open(
f'{path}genre.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_genre = csv.DictReader(csvfile, delimiter=',')
to_db_genre = [
(row['id'], row['name'], row['slug'])
for row in reader_genre
]

with open(
f'{path}titles.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_titles = csv.DictReader(csvfile, delimiter=',')
to_db_titles = [
(row['id'], row['name'], '', row['category'],
row['year'])
for row in reader_titles
]

with open(
f'{path}genre_title.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_genre_title = csv.DictReader(csvfile, delimiter=',')
to_db_genre_title = [
(row['id'], row['title_id'], row['genre_id'])
for row in reader_genre_title
]

with open(
f'{path}review.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_review = csv.DictReader(csvfile, delimiter=',')
to_db_review = [
(row['id'], row['text'], row['score'], row['pub_date'],
row['author'], row['title_id'])
for row in reader_review
]

with open(
f'{path}comments.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_comments = csv.DictReader(csvfile, delimiter=',')
to_db_comments = [
(row['id'], row['text'], row['pub_date'],
row['author'], row['review_id'])
for row in reader_comments
]

with open(
f'{path}users.csv', 'r', newline='', encoding='utf-8'
) as csvfile:
reader_users = csv.DictReader(csvfile, delimiter=',')
to_db_users = [
(row['id'], '', '', '',
row['username'], row['first_name'], row['last_name'],
'', '', '', row['bio'],
row['role'], str(randint(1000000, 10000000)), row['email'])
for row in reader_users
]

cursor.executemany(
'INSERT INTO reviews_category '
'(id, name, slug) VALUES (?, ?, ?)',
to_db_category
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_genre (id, name, slug)'
' VALUES (?, ?, ?)',
to_db_genre
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_title (id, name, description, category_id, year)'
' VALUES (?, ?, ?, ?, ?)',
to_db_titles
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_title_genre (id, title_id, genre_id)'
' VALUES (?, ?, ?)',
to_db_genre_title
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_review '
'(id, text, score, pub_date, author_id, title_id)'
' VALUES (?, ?, ?, ?, ?, ?)',
to_db_review
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_comment '
'(id, text, pub_date, author_id, review_id)'
' VALUES (?, ?, ?, ?, ?)',
to_db_comments
)
conn.commit()
cursor.executemany(
'INSERT INTO reviews_user (id, password, last_login, '
'is_superuser, username, first_name, last_name,'
'is_staff, is_active, date_joined, bio,'
'role, confirmation_code, email)'
' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
to_db_users
)
if not cursor.fetchone():
print(f'Table {table_name} does not exist. Skipping {csv_file}.')
conn.close()
return
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.reader(file)
header = next(csv_reader)
columns = ', '.join(header)
for row in csv_reader:
size = ', '.join(['?'] * len(row))
cursor.execute(
f"INSERT INTO {table_name} ({columns}) VALUES ({size})", row
)
conn.commit()
conn.close()

Expand All @@ -47,10 +142,4 @@ class Command(BaseCommand):

def handle(self, *args, **kwargs) -> None:
"""Обрабатывает импорт данных из CSV-файлов в базу данных SQLite."""
for file, table in zip(files, tables):
try:
print('start download', file)
import_csv_to_sqlite(path + file, table)
print('finish download', file)
except Exception as e:
print(e)
import_csv()
5 changes: 3 additions & 2 deletions api_yamdb/reviews/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Generated by Django 3.2 on 2024-05-25 08:09

from django.conf import settings
import django.contrib.auth.models
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models

import reviews.validators


Expand Down
Loading