Django 视图与路由配置
Django 的视图(View)是处理 HTTP 请求的核心逻辑层,路由(URLconf)则负责将用户请求的 URL 映射到对应的视图函数。本文详细介绍 Django 视图与路由的各种用法。
视图类型对比
- 函数视图(FBV):最基础的视图形式,就是一个 Python 函数,接收 request,返回 response
- 类视图(CBV):基于类的视图,通过继承和 Mixin 提供更丰富的功能,适合标准 CRUD 操作
函数视图(FBV)
# blog/views.py
from django.http import JsonResponse, FileResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_http_methods, require_POST
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from .models import Article
def article_list(request):
if request.method == "GET":
articles = Article.objects.all()[:20]
return render(request, "blog/list.html", {"articles": articles})
elif request.method == "POST":
title = request.POST.get("title")
content = request.POST.get("content")
Article.objects.create(title=title, content=content)
return redirect("article_list")
@require_http_methods(["GET", "POST"])
def edit_article(request, article_id):
article = get_object_or_404(Article, id=article_id)
if request.method == "POST":
article.title = request.POST.get("title", article.title)
article.save()
return redirect("article_detail", slug=article.slug)
return render(request, "blog/edit.html", {"article": article})
@login_required
def dashboard(request):
return render(request, "blog/dashboard.html")
@csrf_exempt
def api_webhook(request):
import json
data = json.loads(request.body)
return JsonResponse({"status": "ok", "received": data})
def api_articles(request):
articles = Article.objects.values("id", "title", "slug", "created_at")
return JsonResponse({"articles": list(articles)}, safe=False)
类视图(CBV)
# blog/views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Article
class ArticleListView(ListView):
model = Article
template_name = "blog/article_list.html"
context_object_name = "articles"
paginate_by = 20
ordering = ["-created_at"]
def get_queryset(self):
queryset = super().get_queryset()
tag = self.request.GET.get("tag")
if tag:
queryset = queryset.filter(tags__name=tag)
return queryset
class ArticleDetailView(DetailView):
model = Article
template_name = "blog/article_detail.html"
context_object_name = "article"
slug_field = "slug"
def get_object(self):
article = super().get_object()
article.views += 1
article.save(update_fields=["views"])
return article
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
fields = ["title", "content", "category"]
template_name = "blog/article_form.html"
success_url = reverse_lazy("article_list")
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ["title", "content", "category"]
template_name = "blog/article_form.html"
def get_success_url(self):
return reverse_lazy("article_detail", kwargs={"slug": self.object.slug})
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
template_name = "blog/article_confirm_delete.html"
success_url = reverse_lazy("article_list")
URL 路由配置
# blog/urls.py
from django.urls import path, re_path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.ArticleListView.as_view(), name="article_list"),
path("article//", views.article_detail, name="article_detail"),
path("article//", views.ArticleDetailView.as_view(), name="article_detail_by_slug"),
path("post//", views.post_by_uuid, name="post_uuid"),
re_path(r"^archive/(?P[0-9]{4})/(?P[0-9]{2})/$", views.archive, name="archive"),
path("create/", views.ArticleCreateView.as_view(), name="article_create"),
path("/edit/", views.ArticleUpdateView.as_view(), name="article_edit"),
path("/delete/", views.ArticleDeleteView.as_view(), name="article_delete"),
]
myproject/urls.py
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls")),
]
URL 反向解析
模板中: {% url "blog:article_detail" slug=article.slug %}
Python 中: reverse("blog:article_detail", kwargs={"slug": "hello-world"})</code></pre><h2>常见问题</h2><ul><li><strong>Q: path 和 re_path 的区别是什么?</strong><br>A:path 使用简洁的转换器语法(如 <int:id>)但不支持正则;re_path 支持完整正则表达式。能用 path 解决的就用 path,更清晰。</li><li><strong>Q: 类视图的 as_view() 是什么?</strong><br>A:as_view() 是类视图的类方法,将类转换为可调用的视图函数。include 到 urlpatterns 时必须加 .as_view(),否则会报「不可调用」错误。</li><li><strong>Q: 如何给类视图添加装饰器?</strong><br>A:使用 @method_decorator 装饰器:<pre><code>from django.utils.decorators import method_decorator
@method_decorator(login_required, name="dispatch")
class MyView(View):
pass
A:HttpResponse 是基础返回对象;render 渲染模板后返回;redirect 返回 302 重定向。