R / Richie全部文章 ↑

Python · 2 分钟阅读

视图基础

视图 = 处理 HttpRequest、返回 HttpResponse 的可调用对象。

最简单的视图

# post/views.py
from django.http import HttpResponse

def hello(request):
    return HttpResponse("<h1>Hello Django</h1>")
# config/urls.py
from django.urls import path
from post import views

urlpatterns = [
    path("post/hello/", views.hello),
]

URLconf 模板

startproject 时生成的注释就是最佳实践示例:

# 函数视图
path("", views.home, name="home")

# 类视图
path("", Home.as_view(), name="home")

# include 分发
path("blog/", include("blog.urls"))

多 App 项目推荐每个 App 自带 urls.py,通过 include 挂载到根 URLconf。

HttpRequest 常用属性

属性 含义
method HTTP 方法
path URL 路径
GET / POST QueryDict,键值都是字符串
FILES 上传文件
META WSGI 元信息(含 IP、UA 等)
user 当前登录用户(或 AnonymousUser)
session 会话字典

request.GET.get("a", 0) 是更安全的取值方式。

HttpResponse 常用子类

  • HttpResponse — 基类
  • JsonResponse — 便捷返回 JSON
  • HttpResponseRedirect — 302 重定向
  • HttpResponseNotFound — 404

类视图(CBV)

from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

class HelloView(View):
    def get(self, request):
        return HttpResponse("GET OK")

    def post(self, request):
        return HttpResponse("POST OK")

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

注册:

path("hello/", HelloView.as_view())

View.dispatch 根据 HTTP 方法自动派发到 get / post / put / delete 等。

Mixin 复用

import time, functools

def exec_time(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        r = func(*args, **kwargs)
        print(f"{func.__name__} took {time.perf_counter() - start:.3f}s")
        return r
    return wrapper

class TimedMixin:
    @method_decorator(exec_time)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

class HelloView(TimedMixin, View):
    ...

Django 内置常用 Mixin:LoginRequiredMixin、UserPassesTestMixin、PermissionRequiredMixin 等。

动态路由

# urls.py
path("dynamic/<int:year>/<mth:month>/<int:day>/", views.dynamic_hello)
转换器 匹配
str 任意非空字符串(默认)
int 整数
slug 字母数字 + - + _
uuid UUID
path 包含 / 的字符串

自定义转换器:

from django.urls import register_converter

class MonthConverter:
    regex = r"0?[1-9]|1[0-2]"
    def to_python(self, value): return int(value)
    def to_url(self, value): return f"{value:02d}"

register_converter(MonthConverter, "mth")

给 post 应用写三个视图

# post/services.py
def build_topic_info(topic):
    return {
        "id": topic.id,
        "title": topic.title,
        "user": topic.user.username,
        "created_time": topic.created_time.isoformat(),
    }

# post/views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from .models import Topic, Comment
from .services import build_topic_info

def topic_list(request):
    qs = Topic.objects.all()
    return JsonResponse({
        "count": qs.count(),
        "results": [build_topic_info(t) for t in qs],
    })

def topic_detail(request, pk):
    topic = get_object_or_404(Topic, pk=pk)
    return JsonResponse(build_topic_info(topic))

def add_comment(request):
    topic = get_object_or_404(Topic, pk=request.POST.get("id", 0))
    content = request.POST.get("content", "")
    if content:
        comment = Comment.objects.create(topic=topic, content=content)
        return JsonResponse({"id": comment.id})
    return JsonResponse({})

get_object_or_404 在 4.2+ 起推荐使用新版快捷方式,与 FBV/CBV 都适配。