Namespace API routes by app and flatten package layout.

Move Django apps out of apps/ and mount them under auth/, common/, content/, and cms/ so endpoint paths map directly to the owning app.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
aifeilong 2026-10-15 08:42:37 +08:00
parent 9f9c5f814f
commit 13b1ca2b9b
43 changed files with 34 additions and 28 deletions

View File

@ -18,10 +18,16 @@ Default local DB is SQLite via `config/local_settings.py`. For PostgreSQL, overr
## API
- Public & staff CRUD: `/api/articles/`, `/api/organizes/`, `/api/subjects/`, `/api/organize-categories/`, `/api/magazine-categories/`, `/api/work-groups/`, `/api/work-group-terms/`, `/api/columns/`, …
- Auth: `POST /api/auth/login/`, `GET /api/auth/me/`
- Django admin: `/django-admin/`
- Search: `GET /api/search/?q=`
路由按 app 划分前缀(网关再统一挂 `/api`):
| 前缀 | App | 示例 |
|------|-----|------|
| `/api/auth/` | `accounts` | `POST /api/auth/login/`、`GET /api/auth/me/` |
| `/api/common/` | `common` | `POST /api/common/uploads/` |
| `/api/content/` | `content` | `/api/content/articles/`、`/api/content/columns/`、… |
| `/api/cms/` | `cms` | `/api/cms/news/`、`GET /api/cms/search/?q=` |
Django admin: `/django-admin/`
Staff write operations require `Authorization: Token <key>` and `is_staff=True`.

View File

@ -3,6 +3,6 @@ from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.accounts"
name = "accounts"
label = "accounts"
verbose_name = "账号"

View File

@ -2,7 +2,7 @@ from decimal import Decimal
from django.core.management.base import BaseCommand
from apps.cms.models import (
from cms.models import (
AboutInfo,
ContactUs,
CopyrightInfo,
@ -12,8 +12,8 @@ from apps.cms.models import (
News,
Publication,
)
from apps.accounts.models import Member
from apps.content.models import (
from accounts.models import Member
from content.models import (
Article,
ArticleComment,
Column,
@ -478,7 +478,7 @@ class Command(BaseCommand):
return created, updated
def _ensure_demo_comments(self):
from apps.accounts.serializers import MemberSerializer
from accounts.serializers import MemberSerializer
# 国际格式;同时兼容旧的 11 位国内号演示数据
member = (

View File

@ -2,7 +2,7 @@
from django.core.management.base import BaseCommand
from apps.content.models import Column, NavPosition
from content.models import Column, NavPosition
# 与 ui/src/config/nav.js 对齐

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.db import models
from apps.common.models import SoftDeleteModel
from common.models import SoftDeleteModel
class Member(SoftDeleteModel):

View File

@ -3,6 +3,6 @@ from django.apps import AppConfig
class CmsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.cms"
name = "cms"
label = "cms"
verbose_name = "站点内容"

View File

@ -1,6 +1,6 @@
from django.db import models
from apps.common.models import SoftDeleteModel
from common.models import SoftDeleteModel
class News(SoftDeleteModel):

View File

@ -9,13 +9,13 @@ from rest_framework.decorators import action
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.response import Response
from apps.content.models import Article, Organize, Professor
from apps.content.serializers import (
from content.models import Article, Organize, Professor
from content.serializers import (
ArticleListSerializer,
OrganizeListSerializer,
ProfessorSerializer,
)
from apps.content.views import IsAdminOrReadOnly, PublicMixin
from content.views import IsAdminOrReadOnly, PublicMixin
ALLOWED_IMAGE_EXT = {".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"}
MAX_UPLOAD_BYTES = 8 * 1024 * 1024

View File

@ -3,6 +3,6 @@ from django.apps import AppConfig
class CommonConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.common"
name = "common"
label = "common"
verbose_name = "公共"

View File

@ -32,7 +32,7 @@ CATEGORY_RE = re.compile(r"^[a-zA-Z0-9_-]{1,32}$")
class MediaUploadView(APIView):
"""POST /api/uploads/ 表单字段: file, category(可选), kind=image|file(可选)"""
"""POST /uploads/ 表单字段: file, category(可选), kind=image|file(可选)"""
permission_classes = [permissions.IsAdminUser]
parser_classes = [MultiPartParser, FormParser]

View File

@ -45,10 +45,10 @@ INSTALLED_APPS = [
"django_extensions",
"simple_history",
"corsheaders",
"apps.common",
"apps.content",
"apps.cms",
"apps.accounts",
"common",
"content",
"cms",
"accounts",
]
MIDDLEWARE = [

View File

@ -5,10 +5,10 @@ from django.urls import include, path
urlpatterns = [
path("django-admin/", admin.site.urls),
path("api/auth/", include("apps.accounts.urls")),
path("api/", include("apps.common.urls")),
path("api/", include("apps.content.urls")),
path("api/", include("apps.cms.urls")),
path("auth/", include("accounts.urls")),
path("common/", include("common.urls")),
path("content/", include("content.urls")),
path("cms/", include("cms.urls")),
]
if settings.DEBUG:

View File

@ -3,6 +3,6 @@ from django.apps import AppConfig
class ContentConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.content"
name = "content"
label = "content"
verbose_name = "内容"

View File

@ -1,6 +1,6 @@
from django.db import models
from apps.common.models import SoftDeleteModel, TimeStampedModel
from common.models import SoftDeleteModel, TimeStampedModel
class NavPosition(models.IntegerChoices):