Django 视图与路由配置

小飞兽 Django 6 次阅读 2026-07-29

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 使用简洁的转换器语法(如 &lt;int:id&gt;)但不支持正则;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

  • Q: HttpResponse、render、redirect 的区别是什么?
    A:HttpResponse 是基础返回对象;render 渲染模板后返回;redirect 返回 302 重定向。

延伸阅读

  • Django 类视图官方文档
  • Django 中间件工作原理深度解析