CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Django 实战入门/课时/Admin 与认证
RawBlame
课时目录12 节

Django 实战入门

  1. 01Django 概览
  2. 02项目结构
  3. 03URL 路由
  4. 04视图层
  5. 05模型与 ORM
  6. 06查询与优化
  7. 07模板 DTL
  8. 08Admin 与认证
  9. 09表单与安全
  10. 10DRF 与异步任务
  11. 11测试与部署
  12. 12综合练习

Admin 与认证

后台、User 模型与权限。

30 分钟

Admin 与认证

这一课你将能做到

  1. 用 Django 自带的 Admin 零代码管理数据,并自定义列表显示、搜索、过滤和操作
  2. 理解 Django 内置 User 模型的字段和扩展方式(AbstractUser vs AbstractBaseUser)
  3. 用 django.contrib.auth 完成登录、登出、权限检查和组管理

为什么要学

Django Admin 是框架最惊艳的功能之一——你定义了模型,自动就能在后台增删改查,不需要额外写一行前端代码。内部管理系统、CMS、内容运营后台,用 Admin 搭建只需几分钟。

和 Spring Boot 对比:Spring 没有内置管理后台,需要自写或用第三方(如 Spring Boot Admin 只监控 JVM)。Django Admin 直接管理业务数据,开箱即用。这是 Django 做内部系统的巨大优势。

先建立图像

管理员访问 /admin/
      │
      ▼
  Django Admin 入口
      │
      ├─ 模型列表(自定义 admin.py 注册)
      │     ├─ Article:列表、搜索、过滤、批量操作
      │     └─ User:内置用户管理
      │
      └─ 认证与授权
            ├─ Users(用户)
            ├─ Groups(组/角色)
            └─ Permissions(权限)

跟着做

步骤 1:开启 Admin 并创建超级用户

python manage.py createsuperuser
# 按提示输入用户名、邮箱、密码

访问 http://127.0.0.1:8000/admin/,用超级用户登录,默认能看到 Users 和 Groups。

步骤 2:注册自定义模型

blog/admin.py:

from django.contrib import admin
from .models import Article, Category, Tag


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ["name", "slug", "created_at"]
    search_fields = ["name"]
    prepopulated_fields = {"slug": ("name",)}  # 根据 name 自动填充 slug


@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    list_display = ["name"]
    search_fields = ["name"]


@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ["title", "author", "category", "status", "views", "created_at", "is_hot"]
    list_filter = ["status", "category", "created_at", "author"]
    search_fields = ["title", "content"]
    list_editable = ["status", "views"]
    list_per_page = 20
    date_hierarchy = "created_at"
    autocomplete_fields = ["author", "category"]  # 外键用搜索框代替下拉(大数据量必备)
    filter_horizontal = ["tags"]                   # 多对多用双列选择器
    actions = ["make_published", "reset_views"]
    fieldsets = [
        ("基本信息", {"fields": ["title", "slug", "author", "category", "tags"]}),
        ("内容", {"fields": ["content"], "classes": ["collapse"]}),
        ("状态", {"fields": ["status", "views"], "classes": ["wide"]}),
    ]

    @admin.action(description="设为已发布")
    def make_published(self, request, queryset):
        queryset.update(status="published")
        self.message_user(request, f"已发布 {queryset.count()} 篇文章")

    @admin.action(description="重置阅读数")
    def reset_views(self, request, queryset):
        from django.db.models import F
        queryset.update(views=0)

    @admin.display(description="热门", boolean=True)
    def is_hot(self, obj):
        return obj.views > 1000

步骤 3:自定义 Admin 外观

# blog/admin.py

admin.site.site_header = "我的博客管理后台"
admin.site.site_title = "管理后台"
admin.site.index_title = "欢迎"

步骤 4:权限系统——用户、组、权限

Django 内置权限模型:

User(用户)←── 多对多 ──→ Group(组)
  │                          │
  └─ 多对多 ──→ Permission(权限)

权限粒度:

  • 模型级:blog.view_article、blog.change_article、blog.add_article、blog.delete_article
  • 对象级(需要额外配置):Django-guardian 等第三方包

视图里检查权限:

from django.contrib.auth.decorators import login_required, permission_required


@login_required
def create_article(request):
    return HttpResponse("创建文章")


@permission_required("blog.change_article", raise_exception=True)
def edit_article(request, pk):
    return HttpResponse(f"编辑文章 {pk}")

CBV 里用 Mixin:

from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import UpdateView


class ArticleUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
    model = Article
    permission_required = "blog.change_article"
    template_name = "blog/article_form.html"

步骤 5:扩展 User 模型

方案 A:继承 AbstractUser(推荐 90% 场景)

# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    avatar = models.ImageField(upload_to="avatars/", blank=True)
    bio = models.TextField(blank=True)
    github = models.URLField(blank=True)

    class Meta:
        verbose_name = "用户"
        verbose_name_plural = "用户"
# settings.py
AUTH_USER_MODEL = "accounts.User"
# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User


@admin.register(User)
class CustomUserAdmin(UserAdmin):
    fieldsets = UserAdmin.fieldsets + (
        ("扩展信息", {"fields": ["avatar", "bio", "github"]}),
    )
    list_display = ["username", "email", "bio", "is_staff"]

方案 B:继承 AbstractBaseUser(完全自定义,只保留密码和最后登录时间)

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models


class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("邮箱必填")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        return self.create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    nickname = models.CharField(max_length=50)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["nickname"]

    objects = UserManager()

关键区别:AbstractUser 保留 username、first_name、last_name、email 等字段,扩展最方便。AbstractBaseUser 是裸机,全自己定义,适合手机号/邮箱登录的非标准场景。

步骤 6:内置认证视图

# urls.py
from django.contrib.auth import views as auth_views

urlpatterns = [
    path("login/", auth_views.LoginView.as_view(template_name="login.html"), name="login"),
    path("logout/", auth_views.LogoutView.as_view(next_page="/"), name="logout"),
    path("password_change/", auth_views.PasswordChangeView.as_view(), name="password_change"),
    path("password_reset/", auth_views.PasswordResetView.as_view(), name="password_reset"),
]

Django 内置了登录、登出、密码修改、密码重置全套视图,你只需要写模板。

讲清楚要点

  1. Admin 的本质是一个自动生成 CRUD 视图的框架:它在启动时扫描 admin.py 里注册的模型,动态生成列表页、编辑页、删除确认页。不是魔法,就是代码生成器。
  2. @admin.register vs admin.site.register:@admin.register 是装饰器写法,更 Pythonic。两者等价。
  3. 超级用户 vs 普通用户 vs 组:超级用户(is_superuser=True)有所有权限;组是把一批权限打包,批量赋给用户。Django 默认权限粒度到模型级别(CRUD),对象级需要第三方。
  4. AUTH_USER_MODEL 必须尽早定:项目启动后改用户模型代价巨大(要重建迁移)。一建项目就要决定用内置 User 还是自定义。
  5. Admin 不是给终端用户用的:它是给内部运营、编辑、管理员用的。终端用户的界面要自己写模板和视图。
  6. raise_exception=True:permission_required 默认未授权时重定向到登录页,加 raise_exception=True 直接返回 403。

你可能会懵的地方

  • 为什么改了 User 模型要删库重来? Django 的 auth_user 表被大量外键引用(如 Article.author),改字段类型或换模型会导致迁移链断裂。最佳实践:项目一启动就定义自定义 User,哪怕目前用不到额外字段。

  • is_staff、is_superuser、is_active 区别? is_active:能否登录。is_staff:能否进 Admin 后台。is_superuser:是否拥有一切权限。可以 is_staff=True 但 is_superuser=False,做受限管理员。

  • 对象级权限是什么? 模型级权限:你能「改所有文章」。对象级:你能「改自己的文章,不能改别人的」。Django 原生不支持,用 django-guardian 或自己写视图逻辑判断 request.user == article.author。

  • PermissionRequiredMixin 和 UserPassesTestMixin 区别? 前者检查权限字符串(如 "blog.change_article"),后者接受自定义 lambda/test 函数。后者更灵活,可以写任意业务规则。

  • Admin 的 raw_id_fields 和 autocomplete_fields 什么时候用? 外键关联的数据超过几百条时,默认下拉框会卡死。raw_id_fields 换成数字输入框 + 放大镜搜索;autocomplete_fields 换成搜索下拉框(更友好)。

错法对照

错法问题正解
项目中期才改 AUTH_USER_MODEL迁移链断裂,数据丢失风险第一步就定义自定义 User
用 User.objects.create() 创建用户密码明文存储User.objects.create_user() 或 set_password()
@login_required 放在 CBV 前面装饰器不生效CBV 用 LoginRequiredMixin,或 @method_decorator(login_required)
Admin 直接暴露给公网安全隐患Admin 配独立域名/IP 白名单,或改 URL 前缀
list_display 里放方法名但不加 @admin.display列名显示方法名加 @admin.display(description="xxx")

卡点急救

  1. 访问 Admin 提示 "You don't have permission":用户 is_staff=False。Admin 只给 staff 用。
  2. 自定义 User 后 migration 报错:之前的迁移还引用旧的 auth.User。删库(开发环境)或手动修迁移文件里的 swappable_dependency。
  3. Admin 里 ForeignKey 下拉几千条导致页面卡死:改用 autocomplete_fields 或 raw_id_fields。

面试常问

  • Django 的权限系统粒度到哪个层面?如何实现对象级权限? 原生到模型级(CRUD 四权限)。对象级需要第三方 django-guardian 或自己在视图里检查所有权。guardian 原理是给每个用户-对象组合分配权限,存额外一张表。

  • AbstractUser 和 AbstractBaseUser 怎么选? 保留 Django 默认用户字段(username、email、first_name 等)时选 AbstractUser。需要完全自定义(如只用手机号/邮箱当用户名、不要 first_name)选 AbstractBaseUser。90% 场景 AbstractUser 够用。

  • 如何限制 Admin 只显示当前用户的数据? 重写 ModelAdmin.get_queryset():

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)
    

自测三问

  1. is_staff、is_superuser、is_active 分别控制什么?
  2. 为什么推荐项目一开始就定义自定义 User 模型?
  3. Admin 的 autocomplete_fields 解决的是什么性能问题?

小结一句话

Django Admin 是零代码生成管理后台的利器,内置认证系统覆盖登录/权限/组;理解 User 模型扩展和权限粒度,是 Django 项目安全管理的基石。

延伸

  • Django 官方文档 - Admin
  • Django 官方文档 - 认证系统
  • 下一课:表单与安全——ModelForm、CSRF、数据校验。
加载本节练习…
← 上一课模板 DTL下一课 →表单与安全