From 23179bb927ac7425389ca10902db7b24be0a03a3 Mon Sep 17 00:00:00 2001 From: Nikolay Shirokov Date: Sun, 15 Jun 2025 21:05:29 +0700 Subject: [PATCH 1/2] feat:add admin for models --- .gitignore | 7 +- apps/books/admin.py | 96 ++++++++++++++++++++++++++- apps/books/migrations/0001_initial.py | 93 ++++++++++++++++++++++++++ apps/books/models.py | 3 + 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 apps/books/migrations/0001_initial.py diff --git a/.gitignore b/.gitignore index e721d1a..eddbcae 100644 --- a/.gitignore +++ b/.gitignore @@ -158,11 +158,14 @@ cython_debug/ #my_folders queries +# macOS +.DS_Store +._.DS_Store # 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 \ No newline at end of file +.idea/ +.ruff_cache diff --git a/apps/books/admin.py b/apps/books/admin.py index 846f6b4..18f1f97 100644 --- a/apps/books/admin.py +++ b/apps/books/admin.py @@ -1 +1,95 @@ -# 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..50521d9 --- /dev/null +++ b/apps/books/migrations/0001_initial.py @@ -0,0 +1,93 @@ +# 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..1c5fc92 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 \ No newline at end of file From 4ad20416ac8e998f9dba2e754718deb7b67064df Mon Sep 17 00:00:00 2001 From: Nikolay Shirokov Date: Sun, 15 Jun 2025 21:09:58 +0700 Subject: [PATCH 2/2] feat:add admin for models with ruff --- apps/books/admin.py | 9 +- apps/books/migrations/0001_initial.py | 220 ++++++++++++++++++++------ apps/books/models.py | 2 +- 3 files changed, 178 insertions(+), 53 deletions(-) diff --git a/apps/books/admin.py b/apps/books/admin.py index 18f1f97..d359ab1 100644 --- a/apps/books/admin.py +++ b/apps/books/admin.py @@ -64,6 +64,7 @@ def get_created(self, obj): get_created.short_description = "Дата создания" + @admin.register(Publisher) class PublisherAdmin(admin.ModelAdmin): list_display = ( @@ -74,9 +75,7 @@ class PublisherAdmin(admin.ModelAdmin): "name", "website", ) - ordering = ( - "name", - ) + ordering = ("name",) @admin.register(Tag) @@ -90,6 +89,4 @@ class TagAdmin(admin.ModelAdmin): "name", "slug", ) - ordering = ( - "name", - ) + ordering = ("name",) diff --git a/apps/books/migrations/0001_initial.py b/apps/books/migrations/0001_initial.py index 50521d9..76f4720 100644 --- a/apps/books/migrations/0001_initial.py +++ b/apps/books/migrations/0001_initial.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ @@ -16,78 +15,207 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Author', + 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='Биография')), + ( + "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': 'Авторы', + "verbose_name": "Автор", + "verbose_name_plural": "Авторы", }, ), migrations.CreateModel( - name='Publisher', + 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='Сайт издательства')), + ( + "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': 'Издательства', + "verbose_name": "Издательство", + "verbose_name_plural": "Издательства", }, ), migrations.CreateModel( - name='Tag', + 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='Цвет')), + ( + "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': 'Теги', + "verbose_name": "Тег", + "verbose_name_plural": "Теги", }, ), migrations.CreateModel( - name='Book', + 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='Теги')), + ( + "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': 'Книги', + "verbose_name": "Книга", + "verbose_name_plural": "Книги", }, ), migrations.CreateModel( - name='Comment', + 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='Пользователь')), + ( + "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': 'Комментарии', + "verbose_name": "Комментарий", + "verbose_name_plural": "Комментарии", }, ), ] diff --git a/apps/books/models.py b/apps/books/models.py index 1c5fc92..3e69fb7 100644 --- a/apps/books/models.py +++ b/apps/books/models.py @@ -146,4 +146,4 @@ class Meta: verbose_name_plural = "Комментарии" def __str__(self): - return self.text \ No newline at end of file + return self.text