Archived
feat: bookmarks and notes management
- Backend: Django REST Framework API with Bookmark and Note models - ViewSets with user-scoped querysets and select_related for N+1 prevention - Create/List/Detail/Update/Delete endpoints - Batch delete operations - Unique constraint on user+book+page for bookmarks - IsOwner permission class for object-level access control - Full serializer validation (page > 0, non-empty content, duplicate check) - 30+ pytest-django tests covering CRUD, auth, filtering, edge cases - Frontend: React TypeScript components - AnnotationsContext with useReducer for state management - BookmarkList, NoteList, AddAnnotationForm, AnnotationsDashboard - Inline note editing with immediate save - Batch delete support - API client with JWT auto-refresh interceptors - Paginated query hook for infinite scroll support - Responsive CSS with loading/empty states - Infrastructure: Django project with custom User model, JWT auth, CORS - PostgreSQL database models with proper FK and indexes - Django admin configuration for all models
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies: list = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Book",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("title", models.CharField(db_index=True, max_length=500)),
|
||||
("author", models.CharField(db_index=True, max_length=300)),
|
||||
("genre", models.CharField(db_index=True, max_length=100)),
|
||||
("description", models.TextField(blank=True, default="")),
|
||||
(
|
||||
"reading_status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("want_to_read", "Want to Read"),
|
||||
("reading", "Reading"),
|
||||
("finished", "Finished"),
|
||||
("dnf", "Did Not Finish"),
|
||||
],
|
||||
db_index=True,
|
||||
default="want_to_read",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
("cover_url", models.URLField(blank=True, default="")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
"ordering": ["title"],
|
||||
"indexes": [
|
||||
models.Index(
|
||||
fields=["title", "author", "genre"],
|
||||
name="books_book_title_2cc25e_idx",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
# migrations/__init__.py
|
||||
Reference in New Issue
Block a user