Django基础教程
Django 是一款高级的 Python Web 框架,旨在快速开发安全且可维护的网站。
pip install Djangopip install djangorestframework3. 基础使用
Section titled “3. 基础使用”3.1. 创建项目
Section titled “3.1. 创建项目”django-admin startproject django-demo3.2. 创建 APP
Section titled “3.2. 创建 APP”django-admin startapp first_app3.3. 运行服务
Section titled “3.3. 运行服务”django-admin runserverpython manage.py runserver3.4. 使用视图
Section titled “3.4. 使用视图”每一个视图表现为一个 Python 函数,必须返回一个 HttpResponse 对象或抛出 Http404 异常。
- 创建视图:
from django.http import HttpResponse
def index(request): return HttpResponse("Hello, world. You're at the polls index.")- 定义 URL:
from django.urls import pathfrom . import views
urlpatterns = [ path('', views.index, name='index'),]- 注册 URL:
from django.contrib import adminfrom django.urls import include, path
urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls),]3.5. 使用模板
Section titled “3.5. 使用模板”- 定义设置:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, # 自动查找各应用下的 templates 目录 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, },]- 定义模板:
{% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> {% endfor %} </ul>{% else %} <p>No polls are available.</p>{% endif %}- 自定义模板过滤器/标签:
import datetimefrom django import template
register = template.Library()
@register.filter # 自定义过滤器def custom_prefix(value, prefix): """ 自定义列表添加前缀过滤器 """ return [f"{prefix}{item}" for item in value]
@register.simple_tag # 自定义标签def current_time(format_string): return datetime.datetime.now().strftime(format_string)- 在视图中调用模板:
from django.template import loaderfrom django.http import HttpResponsefrom .models import Question
def custom_template(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('first_app/index.html') # 加载模板 context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request))3.6. 使用数据库
Section titled “3.6. 使用数据库”- 配置文件:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'django_demo', 'USER': 'root', 'PASSWORD': 'example', 'HOST': '127.0.0.1', 'PORT': '3306', }}- 注册应用:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'first_app.apps.FirstAppConfig']- 创建模型:
from django.db import models
class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published')
class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)- 激活并生成迁移文件:
python manage.py makemigrations first_app- 执行数据库迁移:
# 查看执行迁移的 SQL 语句python manage.py sqlmigrate first_app 0001# 执行真实迁移python manage.py migrate- 增、删、改、查操作:
from django.utils import timezonefrom first_app.models import Choice, Question
# 增q = Question(question_text="What's new?", pub_date=timezone.now())q.save() # 写入数据库
# 查Question.objects.all() # 查询所有记录Question.objects.get(pub_date__year=timezone.now().year) # 根据时间字段查询单个记录Question.objects.filter(question_text__startswith='What') # 根据前缀条件过滤查询Question.objects.get(pk=1) # 主键查询q.choice_set.all() # 关联外键查询
# 改q.question_text = "What's up?"q.save()
# 删q.delete()3.7. 应用调试
Section titled “3.7. 应用调试”使用 Django 内置的 Shell 运行环境进行交互式调试:
python manage.py shell3.8. 数据库迁移
Section titled “3.8. 数据库迁移”对于全新或干净的数据库进行迁移,需要确保:
- 本地生成的所有表结构能正确执行。
- 原库中
django_migrations表中的历史应用迁移记录也应同步导入。
3.9. 管理后台界面
Section titled “3.9. 管理后台界面”- 创建超级管理员账户:
python manage.py createsuperuser本地启动后访问:
http://127.0.0.1:8000/admin。
- 将应用模型注册到管理页面:
from django.contrib import adminfrom .models import Question
admin.site.register(Question)4. 调试与高级应用
Section titled “4. 调试与高级应用”4.1. SimpleUI 后台美化
Section titled “4.1. SimpleUI 后台美化”- 安装:
pip install django-simpleui4.2. Django REST Framework (DRF)
Section titled “4.2. Django REST Framework (DRF)”- 安装:
pip install djangorestframework- 全局配置:
INSTALLED_APPS = [ ... 'rest_framework',]
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAdminUser', ], 'PAGE_SIZE': 10}- 数据序列化配置 (Serializers):
from django.contrib.auth.models import Userfrom rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer): answer = serializers.SerializerMethodField()
def __init__(self, *args, custom_record_id=None, **kwargs): """支持动态传参初始化""" super(UserSerializer, self).__init__(*args, **kwargs) self.custom_record_id = custom_record_id
def get_answer(self, obj): """使用自定义 SerializerMethodField 进行个性化序列化""" raws = RecordAndAnswer.objects.filter(question=obj.id, record=self.custom_record_id) ids = [] instances = [] for item in raws: if item.answer_id not in ids: instances.append(item.answer) ids.append(item.answer_id) return RecordAnswerSerializer(instances, many=True).data
class Meta: model = User fields = ('url', 'username', 'email', 'groups', 'answer')
class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ('id', 'title', 'code', 'linenos', 'language', 'style')- 视图配置 (Views):
from rest_framework import statusfrom rest_framework.decorators import api_viewfrom rest_framework.response import Responsefrom rest_framework.views import APIViewfrom rest_framework import mixinsfrom rest_framework import generics
# 函数式 API 视图@api_view(['GET', 'POST'])def snippet_list(request): """ 列出所有代码片段,或者创建一个新的代码片段。 """ if request.method == 'GET': snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data)
elif request.method == 'POST': serializer = SnippetSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# 类视图 (APIView)class SnippetList(APIView): def get(self, request, format=None): snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data)
def post(self, request, format=None): serializer = SnippetSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# 结合 Mixins 的通用视图class SnippetDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = Snippet.objects.all() serializer_class = SnippetSerializer
def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)- 序列化应用方式:
# 序列化单条数据并转为 JSON 字节流serializer = SnippetSerializer(snippet)content = JSONRenderer().render(serializer.data)
# 反序列化 JSON 字节流并校验数据import iofrom rest_framework.parsers import JSONParserstream = io.BytesIO(content)data = JSONParser().parse(stream)serializer = SnippetSerializer(data=data)4.3. Drf-spectacular 自动接口文档生成
Section titled “4.3. Drf-spectacular 自动接口文档生成”- 在类视图中声明:
from rest_framework.views import APIViewfrom .serializers import CaptchaResSerializer
class CaptchaAPI(APIView): serializer_class = CaptchaResSerializer # 明确指定序列化器供文档生成器解析 def get(self, request): pass- 在函数视图中声明:
from rest_framework.decorators import api_viewfrom drf_spectacular.utils import extend_schema
@extend_schema(responses={200: CaptchaResSerializer, 404: CaptchaResSerializer}, request=CaptchaResSerializer)@api_view(['POST'])def test_view(request): """ 测试视图的详细描述说明。 """ return Response({"message": "Hello, world!"})- 自定义接口参数声明:
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
@extend_schema( parameters=[ OpenApiParameter(name='artist', description='Filter by artist', required=False, type=str), OpenApiParameter( name='release', type=OpenApiTypes.DATE, location=OpenApiParameter.QUERY, description='Filter by release date', ), ], responses={200: CaptchaResSerializer, 404: CaptchaResSerializer}, request=CaptchaResSerializer, description='更详细的 API 覆盖描述。')def post(request): pass- 在 Serializer 级自定义字段展示:
from drf_spectacular.utils import extend_schema_serializer, OpenApiExample
@extend_schema_serializer( exclude_fields=('image_url',), # 明确指定生成接口文档时需隐藏的内部字段 examples = [ OpenApiExample( 'Valid example 1', summary='字段示例说明', description='更长的主体功能介绍', value={ 'songs': {'top10': True}, 'single': {'top10': True} }, request_only=True, response_only=True, ), ])class CaptchaResSerializer(serializers.Serializer): status = serializers.IntegerField() key = serializers.CharField() image_url = serializers.CharField() users = UserSerializer(read_only=True, many=True) test = serializers.SerializerMethodField() # 注意:只读的 Method 字段默认不显示在 Request 文档中
def get_test(self): return "test_field"4.4. 注册自定义 django-admin 命令行
Section titled “4.4. 注册自定义 django-admin 命令行”- 标准应用命令目录结构:
polls/ __init__.py models.py management/ __init__.py commands/ __init__.py _private.py closepoll.py # 自定义运行脚本名称 tests.py views.py- 编写的
closepoll.py脚本内容:
from django.core.management.base import BaseCommand, CommandErrorfrom polls.models import Question as Poll
class Command(BaseCommand): help = "关闭指定投票的投票功能"
def add_arguments(self, parser): # 声明命令行参数 parser.add_argument("poll_ids", nargs="+", type=int)
def handle(self, *args, **options): for poll_id in options["poll_ids"]: try: poll = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise CommandError('Poll "%s" does not exist' % poll_id)
poll.opened = False poll.save()
self.stdout.write( self.style.SUCCESS('Successfully closed poll "%s"' % poll_id) )4.5. Django-celery-beat 异步定时任务
Section titled “4.5. Django-celery-beat 异步定时任务”- 安装:
pip install django-celery-beat5. 拓展与常见错误排查
Section titled “5. 拓展与常见错误排查”5.1. populate() Isn't Reentrant 异常解决
Section titled “5.1. populate() Isn't Reentrant 异常解决”当在初始化过程中多次不当重载 apps 注册表时,可能会触发此并发重入机制异常。
- 修复方案:
定位到 Python 环境路径下的
django/apps/registry.py,将引发该错误的行替代并修复为:
# 替换原 raise RuntimeError("populate() isn't reentrant") 为self.app_configs = {}