diff --git a/.gitignore b/.gitignore index d6a29e2..462824c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,37 @@ +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -9,7 +43,6 @@ __pycache__/ # Distribution / packaging .Python build/ -build_data/ develop-eggs/ dist/ downloads/ @@ -83,7 +116,6 @@ target/ profile_default/ ipython_config.py - # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: @@ -117,7 +149,6 @@ __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid -client_data.json # SageMath parsed files *.sage.py @@ -134,7 +165,6 @@ venv.bak/ # Spyder project settings .spyderproject .spyproject -client_data.json # Rope project settings .ropeproject @@ -156,15 +186,22 @@ dmypy.json # Cython debug symbols cython_debug/ -#my_folders -queries - # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ -.ruff_cache +.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json -pgdata/ \ No newline at end of file +# docker volumes +pgdata/ diff --git a/apps/books/admin.py b/apps/books/admin.py index 846f6b4..d359ab1 100644 --- a/apps/books/admin.py +++ b/apps/books/admin.py @@ -1 +1,92 @@ -# Register your models here. +from django.contrib import admin + +from apps.books.models import Author, Book, Comment, Publisher, Tag + + +@admin.register(Author) +class AuthorAdmin(admin.ModelAdmin): + list_display = ( + "first_name", + "last_name", + "bio", + ) + search_fields = ( + "first_name", + "last_name", + ) + ordering = ( + "first_name", + "last_name", + ) + + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + list_display = ( + "title", + "authors_list", + "published_at", + "isbn_code", + "language", + ) + list_filter = ( + "language", + "publisher", + "tags", + ) + search_fields = ( + "title", + "isbn_code", + "description", + ) + + def authors_list(self, obj): + return ", ".join([str(a) for a in obj.author.all()]) + + authors_list.short_description = "Авторы" + + +@admin.register(Comment) +class CommentAdmin(admin.ModelAdmin): + list_display = ( + "user", + "text", + "book", + "get_created", + ) + list_filter = ( + "user", + "book", + ) + + def get_created(self, obj): + return obj.created + + get_created.short_description = "Дата создания" + + +@admin.register(Publisher) +class PublisherAdmin(admin.ModelAdmin): + list_display = ( + "name", + "website", + ) + search_fields = ( + "name", + "website", + ) + ordering = ("name",) + + +@admin.register(Tag) +class TagAdmin(admin.ModelAdmin): + list_display = ( + "name", + "slug", + "color", + ) + search_fields = ( + "name", + "slug", + ) + ordering = ("name",) diff --git a/apps/books/migrations/0001_initial.py b/apps/books/migrations/0001_initial.py new file mode 100644 index 0000000..76f4720 --- /dev/null +++ b/apps/books/migrations/0001_initial.py @@ -0,0 +1,221 @@ +# Generated by Django 5.2.1 on 2025-06-09 13:25 + +import django.db.models.deletion +import django_extensions.db.fields +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Author", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "first_name", + models.CharField(max_length=100, verbose_name="Имя автора"), + ), + ( + "last_name", + models.CharField(max_length=100, verbose_name="Фамилия автора"), + ), + ("bio", models.TextField(blank=True, verbose_name="Биография")), + ], + options={ + "verbose_name": "Автор", + "verbose_name_plural": "Авторы", + }, + ), + migrations.CreateModel( + name="Publisher", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField( + max_length=255, verbose_name="Название издательства" + ), + ), + ( + "website", + models.URLField( + blank=True, max_length=255, verbose_name="Сайт издательства" + ), + ), + ], + options={ + "verbose_name": "Издательство", + "verbose_name_plural": "Издательства", + }, + ), + migrations.CreateModel( + name="Tag", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField( + max_length=100, unique=True, verbose_name="Название тега" + ), + ), + ( + "slug", + models.SlugField( + max_length=100, unique=True, verbose_name="URL-имя" + ), + ), + ("color", models.CharField(max_length=20, verbose_name="Цвет")), + ], + options={ + "verbose_name": "Тег", + "verbose_name_plural": "Теги", + }, + ), + migrations.CreateModel( + name="Book", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created", + django_extensions.db.fields.CreationDateTimeField( + auto_now_add=True, verbose_name="created" + ), + ), + ( + "modified", + django_extensions.db.fields.ModificationDateTimeField( + auto_now=True, verbose_name="modified" + ), + ), + ( + "title", + models.CharField(max_length=255, verbose_name="Название книги"), + ), + ("description", models.TextField(verbose_name="Описание книги")), + ("published_at", models.DateField(verbose_name="Дата публикации")), + ( + "isbn_code", + models.CharField(max_length=20, unique=True, verbose_name="ISBN"), + ), + ("total_pages", models.IntegerField(verbose_name="Количество страниц")), + ( + "cover_image", + models.URLField(max_length=255, verbose_name="Обложка книги"), + ), + ("language", models.CharField(max_length=50, verbose_name="Язык")), + ( + "author", + models.ManyToManyField( + related_name="books", to="books.author", verbose_name="Авторы" + ), + ), + ( + "publisher", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="books", + to="books.publisher", + verbose_name="Издательство", + ), + ), + ( + "tags", + models.ManyToManyField( + related_name="books", to="books.tag", verbose_name="Теги" + ), + ), + ], + options={ + "verbose_name": "Книга", + "verbose_name_plural": "Книги", + }, + ), + migrations.CreateModel( + name="Comment", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created", + django_extensions.db.fields.CreationDateTimeField( + auto_now_add=True, verbose_name="created" + ), + ), + ( + "modified", + django_extensions.db.fields.ModificationDateTimeField( + auto_now=True, verbose_name="modified" + ), + ), + ("text", models.TextField(verbose_name="Комментарий")), + ( + "book", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="comments", + to="books.book", + verbose_name="Книга", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="comments", + to=settings.AUTH_USER_MODEL, + verbose_name="Пользователь", + ), + ), + ], + options={ + "verbose_name": "Комментарий", + "verbose_name_plural": "Комментарии", + }, + ), + ] diff --git a/apps/books/models.py b/apps/books/models.py index 620dd50..3e69fb7 100644 --- a/apps/books/models.py +++ b/apps/books/models.py @@ -144,3 +144,6 @@ class Comment(TimeStampedModel): class Meta: verbose_name = "Комментарий" verbose_name_plural = "Комментарии" + + def __str__(self): + return self.text