ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Django全栈博客实战:从模型设计到WebSocket实时推送

Django全栈博客实战:从模型设计到WebSocket实时推送 一提到全栈开发很多人第一反应是前端工程化加后端API接口最后再用Nginx把它们缝在一起。但如果你选的是Django全栈这件事会踏实很多——数据库操作、业务逻辑、HTML渲染和个人相关的认证授权都在一个框架里完成整个博客系统从前到后是一套代码。我做过各种博客类的项目从个人笔记站到多作者内容平台每个项目最后都回归到Django。这篇教程不是从零复刻一个复杂CMS而是把博客系统的主干——文章发布、分类标签、评论互动、登录编辑、搜索订阅——按真实开发顺序串起来。适合已经会一点Python、但没完整做过网站的人。学完之后你能对Django的全栈流程有整体认知模型怎么建、路由怎么配、模板怎么渲染以及登录状态下浏览器和服务器之间究竟发生了什么。1. 博客系统这种项目为什么是Django的主场1.1 一个博客系统到底需要哪些核心功能先冷静拆一下需求。一个能用的博客系统最核心的其实就五条文章能发布、能编辑、能删除文章有分类和标签方便读者筛内容读者能看详情、能翻列表最好还能评论站长需要登录后台管理内容再往上走可能会有站内搜索、RSS订阅、数据推送这类增强功能。听起来不多但每一条背后都牵扯一整条链路。文章发布要处理表单校验、数据库写入、权限判断分类和标签要设计多对多关系评论要防垃圾、要关联文章后台管理如果自己从零写光增删改查的页面就要做好几套。很多新手在这里就被劝退了于是转头去用WordPress或者现成的博客框架。但问题在于用现成CMS你对数据模型和业务流程的控制力很弱想改一个字段、想换一套推荐逻辑都得跟系统底层较劲。Django的聪明之处在于它预先把这套链路里最重的那几块打包好了。你要做的是理解这些组件怎么协同然后集中在业务层写自己的东西。这也是我始终推荐用Django做博客系统的原因——它给你的不是模板而是一整套能落地的基建。1.2 Django的内置武器与选型对比先看Django自带什么。ORM把Python类和数据库表做了映射你不需要手写SQL大部分查询用一行代码就能表达自带Admin后台模型注册之后就有了配套的增删改查界面认证系统覆盖了用户、登录、会话、权限最常用的那套登录机制开箱即用模板系统负责服务端渲染把数据直接填充成HTML返回给浏览器。如果说这些是零件那Django的高明之处在于零件之间咬合得特别好。ORM查出来的数据可以直接塞进模板认证系统能装饰视图函数Admin可以定制字段和操作方式。这跟拼积木不一样更像是一辆出厂时就组装好的车你只需要决定开去哪。对比一下其他路线就更能理解。Flask很轻但你要自己选ORM、自己集成认证插件自由度换来的是决策成本Node.js写博客也可以但生态里的框架组合方式太多对新手反而混乱Java系里如果是从MyBatis那套手写SQL映射过来的会有一段适应期才能习惯对象即表的直觉。Django沉淀了十几年对博客这类内容型项目几乎处处命中要害。方案学习成本自带能力适合人群Django中完整想快速做出完整全栈网站的人Flask低起步少而精喜欢自己拼装的技术爱好者Node/Express中中想在JS生态里做前后端的人Java/Spring高强大但重企业级场景结论很简单如果你要做的是博客系统、内容站点、内部管理系统这种服务端渲染为主的网站Django是投入产出比最高的选择。先别急着上前后端分离后面我会解释为什么全栈模式的Django对新手更友好。2. 开发环境准备与项目初始化先跑起来再谈功能2.1 Python版本与虚拟环境的坑开始写代码前环境这块值得多花五分钟。Python版本建议直接用3.10及以上Django跑起来更省心。这里有个老坑如果你用系统自带的pip直接装包很容易污染全局环境过几个月你会发现某个项目要Django 3.x另一个要5.x两者根本没法共存。解决办法是用虚拟环境。创建和激活的命令如下python3 -m venv venv source venv/bin/activate # Windows下是 venv\Scripts\activate pip install django pip install --upgrade pip激活成功之后命令行前面会出现(venv)前缀。我用这个习惯做了好几个项目从没因为依赖冲突翻过车。版本选择上建议装当前的稳定LTS版本比如Django 4.2或者5.x因为LTS有更长时间的安全维护博客这种要长期跑的项目选LTS心里踏实。2.2 创建项目和appdjango-admin与startappDjango里有两个概念特别容易混淆项目project和应用app。项目是整个网站比如我的博客平台应用是项目里的一个功能模块比如文章模块评论模块。多app结构能让你之后扩展功能时不把代码堆成一团。创建命令很简单django-admin startproject blog_project . python manage.py startapp blog python manage.py startapp comment注意第一条命令末尾的.表示在当前目录内生成项目文件目录结构会比较干净。项目创建好之后你会看到manage.py、blog_project/settings.py、urls.py这些文件。紧接着第二步也是很多人最容易漏掉的把新建的app注册到配置文件里。# blog_project/settings.py INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, blog, comment, ]不注册的话Django根本不知道你的模型存在执行迁移的时候会报类似App blog could not be found的错误。这一步是新手报错的重灾区。2.3 settings.py里必改的三处配置打开settings.py不用急着全看懂先改三处。第一处是ALLOWED_HOSTS。开发阶段可以先设成ALLOWED_HOSTS [*]省得访问时出现DisallowedHost报错。将来部署时必须改成实际域名这个我后面部署章节会强调。第二处是语言和时区。默认是英文和UTC时间中文博客肯定要改成LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ True改完这两项后Admin后台会变成中文时间显示也跟着本地化。关于USE_TZ很多新手容易懵简单说就是数据库存UTC、展示时按当地时区转换这是好习惯博客发布时间的排序不会乱。第三处是数据库。默认是SQLite就是一个文件零配置开发期直接用DATABASES { default: { ENGINE: django.db.backends.sqlite3, NAME: BASE_DIR / db.sqlite3, } }改完这三处运行两条命令就能看到初始页面python manage.py migrate python manage.py runserver浏览器打开http://127.0.0.1:8000看到火箭升空页面项目骨架就算跑通了。migrate会创建Django自带的表比如用户表、会话表这些后面登录功能会用到。3. 博客系统的数据模型把文章、分类、标签、评论的关系理清楚3.1 建模思路数据库设计先想关系我做过的所有博客项目里最花时间琢磨的不是页面样式而是数据模型设计。数据库设计就像一个房子的框架框架歪了后面装修全是补丁。先想清楚实体之间的关系。一篇文章属于一个分类分类是一对多关系一篇文章可以有多个标签标签也可以挂在多篇文章上这是多对多关系评论挂在文章下一篇文章有多条评论又是一对多关系用户跟文章之间一个用户可以写多篇文章也是一对多。这些关系一旦想清楚模型代码基本就是照着写。我见过不少新手一上来就给每篇文章单独建一张表或者把标签做成一个字符串存进同一列后面做筛选就痛苦了。数据库设计阶段多花半小时等于给未来的功能省下好几天。3.2 核心模型代码Category、Tag、Post在blog/models.py里写from django.db import models from django.urls import reverse class Category(models.Model): name models.CharField(分类名, max_length50) slug models.SlugField(标识, uniqueTrue) class Meta: verbose_name 分类 verbose_name_plural verbose_name def __str__(self): return self.name class Tag(models.Model): name models.CharField(标签名, max_length50) slug models.SlugField(标识, uniqueTrue) class Meta: verbose_name 标签 verbose_name_plural verbose_name def __str__(self): return self.name class Post(models.Model): title models.CharField(标题, max_length200) slug models.SlugField(链接标识, uniqueTrue) author models.ForeignKey(auth.User, on_deletemodels.CASCADE, verbose_name作者) category models.ForeignKey(Category, on_deletemodels.SET_NULL, nullTrue, verbose_name分类) tags models.ManyToManyField(Tag, blankTrue, verbose_name标签) body models.TextField(正文) created_time models.DateTimeField(创建时间, auto_now_addTrue) updated_time models.DateTimeField(更新时间, auto_nowTrue) views models.PositiveIntegerField(浏览量, default0) class Meta: ordering [-created_time] verbose_name 文章 verbose_name_plural verbose_name def __str__(self): return self.title def get_absolute_url(self): return reverse(blog:detail, args[self.pk])几个细节值得解释。slug用于生成语义化的URL比post?id3更友好而且搜索引擎也喜欢。author直接用Django自带User模型省去自己建用户表category用了SET_NULL万一某个分类被删除文章还能保留只是分类变成空views字段做浏览量计数开发期就预留好避免上线后加字段要改表结构的麻烦。3.3 评论模型与删除行为Django执行查询-删除对象时到底发生了什么评论模型放在comment/models.pyfrom django.db import models class Comment(models.Model): post models.ForeignKey(blog.Post, on_deletemodels.CASCADE, related_namecomments, verbose_name文章) name models.CharField(昵称, max_length50) email models.EmailField(邮箱) content models.TextField(内容) is_show models.BooleanField(是否显示, defaultTrue) created_time models.DateTimeField(创建时间, auto_now_addTrue) class Meta: ordering [created_time] verbose_name 评论 verbose_name_plural verbose_name def __str__(self): return {}: {}.format(self.name, self.content[:20])这里的on_deletemodels.CASCADE值得展开说说。它的含义是当一篇文章被删除所有关联评论会跟着一起删除。假设数据库中执行Post.objects.get(pk1).delete()Django会自动查出所有外键指向这篇文章的评论然后一并删掉。如果评论表特别大这个过程会有一定的性能损耗但博客场景完全可接受。在删除行为上on_delete有几种常见选择参数行为使用场景CASCADE关联数据一起删除评论、附件等从属数据SET_NULL外键置空文章删了但分类保留PROTECT有引用则拒绝删除核心不可丢失的关联数据SET_NULL要求外键字段必须设置nullTrue否则会报错。数据库设计阶段就得想好哪些数据是主心骨哪些是跟班。分类一般不会轻易删即使用SET_NULL保护文章评论则完全附属于文章级联删除最省心。3.4 数据迁移与Admin后台验证模型写完执行python manage.py makemigrations python manage.py migratemakemigrations会根据模型变化生成迁移文件migrate把迁移实际应用到数据库。每次增删字段都要重复这两步算是开发期的肌肉记忆。然后到blog/admin.py里注册模型from django.contrib import admin from .models import Category, Tag, Post admin.site.register(Category) admin.site.register(Tag) admin.site.register(Post)comment/admin.py里同样注册 Comment。创建超级用户python manage.py createsuperuser进入http://127.0.0.1:8000/admin登录后你就能在后台手动添加分类、标签和文章了。这一步特别重要因为接下来的页面开发需要真实数据来调试。Admin后台是Django项目开发期的一大利器相当于免费送你一个测试数据录入工具。4. 从数据库到页面视图、路由、模板的三层协作4.1 视图层选型函数视图打底类视图提效模型有了接下来要让文章在前台页面显示出来。这里会同时看到函数视图和类视图两种写法。我的建议新手先把函数视图写明白再切换到类视图。先看文章列表的函数视图from django.shortcuts import render, get_object_or_404 from .models import Post from django.core.paginator import Paginator def post_list(request): posts Post.objects.all() paginator Paginator(posts, 5) page_number request.GET.get(page) page_obj paginator.get_page(page_number) return render(request, blog/post_list.html, {page_obj: page_obj})逻辑很直白查数据、做分页、渲染模板。再看详情页def post_detail(request, pk): post get_object_or_404(Post, pkpk) comments post.comments.filter(is_showTrue) return render(request, blog/post_detail.html, {post: post, comments: comments})get_object_or_404很实用文章不存在时直接返回404页面省得自己判断。函数视图看明白之后类视图的效率优势就体现出来了。用Django内置的ListView和DetailView上面的逻辑可以简化成from django.views.generic import ListView, DetailView class PostListView(ListView): model Post template_name blog/post_list.html context_object_name posts paginate_by 5 class PostDetailView(DetailView): model Post template_name blog/post_detail.html类视图把增删改查的共同逻辑抽象好了代码量直接减半。但我不建议一上来就用类视图因为你如果不理解它底层做的事情遇到需要定制的地方就会卡壳。先写几遍函数视图再切到类视图两种模式都通。4.2 URL路由设计路径规划在blog/urls.py里from django.urls import path from . import views app_name blog urlpatterns [ path(, views.post_list, namelist), path(post/int:pk/, views.post_detail, namedetail), ]项目根路由里套一层from django.urls import include, path urlpatterns [ path(admin/, admin.site.urls), path(, include(blog.urls)), ]app_name blog是命名空间这样就算以后有多个app都有list这个名称模板里用{% url blog:list %}也不会冲突。路径中int:pk是路径转换器Django会把URL里的数字捕获后作为pk参数传给视图。如果你想用文章标题写URL可以换成slug:slug但要保证slug全局唯一。4.3 模板继承与静态资源模板是服务端渲染的最后一公里。新建templates/base.html!DOCTYPE html html langzh head meta charsetUTF-8 title{% block title %}我的博客{% endblock %}/title /head body {% block content %}{% endblock %} /body /html子模板继承{% extends base.html %} {% block title %}文章列表{% endblock %} {% block content %} {% for post in posts %} h2a href{{ post.get_absolute_url }}{{ post.title }}/a/h2 p{{ post.created_time }}/p {% endfor %} {% endblock %}静态文件需要先创建blog/static/blog/目录然后把style.css放进去。模板顶部用{% load static %}加载再通过link relstylesheet href{% static blog/style.css %}引用。注意路径里一定要带上app名前缀这是Django静态文件查找的规定。4.4 分页与列表页模板分页后的列表页模板里需要判断当前页并渲染翻页链接div {% if page_obj.has_previous %} a href?page{{ page_obj.previous_page_number }}上一页/a {% endif %} 第 {{ page_obj.number }} / {{ page_obj.paginator.num_pages }} 页 {% if page_obj.has_next %} a href?page{{ page_obj.next_page_number }}下一页/a {% endif %} /div分页器默认传的上下文变量名是page_obj这也是Django的约定俗成。自己用Paginator分页时注意变量名保持一致模板才不会空。4.5 发表文章全栈业务流程的完整闭环博客不只是展示还得能发文章。在后台Admin里写文章算一种但作为全栈开发前台也要有文章发布表单。这里用Django的ModelForm最省事from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model Post fields [title, slug, category, tags, body]模板里form methodpost {% csrf_token %} {{ form.as_p }} button typesubmit发布/button /form视图处理POST逻辑时核心步骤是先验证表单再入库def post_create(request): if request.method POST: form PostForm(request.POST) if form.is_valid(): post form.save(commitFalse) post.author request.user post.save() form.save_m2m() return redirect(blog:detail, pkpost.pk) else: form PostForm() return render(request, blog/post_form.html, {form: form})commitFalse的意义是先不落库把表单里没有的author字段补上再真正保存。多对多字段tags需要在模型保存后再调form.save_m2m()把关系表写入。这是新手最容易漏的一步漏了之后文章保存成功但标签永远是空的。5. 登录认证与状态管理Cookie和Token是怎么工作的5.1 Django内置认证系统接入文章发布表单里用了request.user但这个用户必须是登录状态否则就是个匿名对象。 Django内置认证系统提供了完整的登录流程你需要做的是把它接进自己的页面。from django.contrib.auth import login, logout from django.contrib.auth.decorators import login_required给需要登录才能操作的视图加上login_required装饰器login_required def post_create(request): ...同时配置文件里加一行告诉Django未登录时跳去哪LOGIN_URL /login/登录页视图直接用Django内置的LoginView就能搞定from django.contrib.auth.views import LoginView, LogoutView urlpatterns [ path(login/, LoginView.as_view(template_nameblog/login.html), namelogin), path(logout/, LogoutView.as_view(), namelogout), ]广播一下创建超级用户时用的createsuperuser创建的就是Django默认User模型的实例跟你网站前台登录用户是同一套不需要额外写注册逻辑。如果博客需要开放注册就用UserCreationForm扩展一个注册视图。5.2 从Session到Cookie再到Token一个容易混淆的三角关系搜 django cookie 设置 token 能搜出一大堆问题说明新手在这块真的会绕晕。我尝试把关系讲透。HTTP协议本身是无状态的服务器不记得你上次访问过。为了记住登录状态浏览器拿到一个凭证每次请求带上它。Django默认用Session机制用户登录成功后Django在服务器端生成一条Session记录同时把sessionid这个值写进浏览器Cookie。浏览器随后的每个请求都会带上这个CookieDjango据此判断你确实是刚才登录的那个人。那Token又是什么Token是另一种凭证形式典型的像JWT。它把所有会话信息直接加密塞进字符串里发给前端服务器不保存会话记录靠密钥验证这个字符串的合法性。所以Token特别适合前后端分离的项目、移动端App调用API的场景。在Django全栈博客里我的建议是别急着用Token。原因很简单Session方案更难被攻击天然有服务端兜底还能配合CSRF防护一起工作。Token虽然开发方便但要自己处理刷新、过期、保密存储一旦泄露等于把用户的通行证原样给了别人。如果你确实需要在Django里手动设置自定义Cookie可以用response.set_cookie(key, value, max_age...)想在请求里读取用request.COOKIES.get(key)。但请只在采集偏好、记录访客身份这类场景用不要把用户登录状态放进自定义Cookie里绕开Session那是舍本逐末。5.3 让只有作者能改落地权限控制的两种写法博客系统一定要有权限控制。最简单的场景只有文章作者本人能编辑和删除自己的文章。可以用装饰器也可以重写类视图的dispatch。装饰器方案from django.http import Http404 login_required def post_edit(request, pk): post get_object_or_404(Post, pkpk) if post.author ! request.user: raise Http404(无权操作) ...类视图方案from django.views.generic import UpdateView class PostUpdateView(UpdateView): model Post form_class PostForm template_name blog/post_form.html def dispatch(self, request, *args, **kwargs): post self.get_object() if post.author ! request.user: raise Http404(无权操作) return super().dispatch(request, *args, **kwargs)权限校验的逻辑并不复杂关键是别漏。我见过有人只在前台模板里隐藏编辑按钮后台URL却仍然能访问等于门锁装在门把手上。服务端每个写操作都要自己校验一遍这是底线。6. 给博客加几个提气功能搜索、订阅与WebSocket实时通知6.1 站内搜索两种实现Q对象与全文检索给小博客做站内搜索用ORM的Q对象就够了。from django.db.models import Q def post_search(request): keyword request.GET.get(q, ) posts Post.objects.filter( Q(title__icontainskeyword) | Q(body__icontainskeyword) ) return render(request, blog/search.html, {posts: posts, keyword: keyword})__icontains对应SQL里的LIKE %keyword%忽略大小写。一个Q对象表示一个查询条件用管道符|合并就是或的逻辑。标题命中和正文命中都能搜到。这个方案在文章量几百上千时完全够用。等文章过万LIKE查询会变慢那时候再考虑全文检索。 Postgres数据库可以用内置全文搜索或者用Whoosh这类纯Python全文搜索引擎。但对这篇入门教程来说Q对象是你现在就能上手的方案不要过度设计。6.2 RSS订阅一页纸博客没RSS总觉得缺点什么。Django里做RSS Subscribe非常简单新建一个feeds.pyfrom django.contrib.syndication.views import Feed from django.urls import reverse from .models import Post class LatestPostsFeed(Feed): title 我的博客最新文章 link / description 最新更新的博客文章 def items(self): return Post.objects.all()[:10] def item_title(self, item): return item.title def item_link(self, item): return reverse(blog:detail, args[item.pk])路由里注册path(rss/, LatestPostsFeed(), namerss),浏览器访问/rss/就能看到标准的XML订阅内容。放到导航栏里给习惯用RSS阅读器的读者留一条通道。6.3 WebSocket实现后台数据推送到前端热搜词里出现 python django websocket实现后台有数据前端推送说明不少人想用Django做实时推送。经典场景是后台有数据更新前端页面不用刷新就能收到通知。传统HTTP做不到服务器主动推送需要WebSocket长连接。Django官方对WebSocket的支持是通过Channels库扩展的。实现方案分三步。第一步安装并配置channelspip install channels# blog_project/settings.py INSTALLED_APPS [ ..., channels, ] ASGI_APPLICATION blog_project.asgi.application并创建一个routing.py定义路由from django.urls import path from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from blog import consumers application ProtocolTypeRouter({ http: get_asgi_application(), websocket: AuthMiddlewareStack( URLRouter([ path(ws/notify/, consumers.NoticeConsumer.as_asgi()), ]) ), })第二步写消费者。消费者是WebSocket连接的处理逻辑。# blog/consumers.py import json from channels.generic.websocket import AsyncWebsocketConsumer class NoticeConsumer(AsyncWebsocketConsumer): async def connect(self): await self.channel_layer.group_add(notify_group, self.channel_name) await self.accept() async def disconnect(self, close_code): await self.channel_layer.group_discard(notify_group, self.channel_name) async def notify_event(self, event): await self.send(text_datajson.dumps(event[message]))第三步前端页面用JavaScript建立连接const ws new WebSocket(ws:// window.location.host /ws/notify/); ws.onmessage function(e) { const data JSON.parse(e.data); alert(新通知 data.text); };后台业务代码里当发生某个事件比如新文章发布、新评论提交直接向该Group广播from asgiref.sync import async_to_sync from channels.layers import get_channel_layer channel_layer get_channel_layer() async_to_sync(channel_layer.group_send)( notify_group, {type: notify_event, message: {text: 有新的文章发布了}} )实话实说对大多数个人博客WebSocket并不是刚需。真正常用的是消息通知、在线人数统计这类场景。如果你只是想要评论动态刷新不少时候轮询反而更简单。我建议把这套能力当成扩展点预留等确实有实时性需求时再加不要第一版就往里塞。6.4 后台美化django-unfold与simpleuiDjango自带的Admin后台功能没得说但界面停留在工程风。想给后台换个现代点的皮肤可以关注两个项目django-unfold和simpleui。simpleui界面简洁流畅文档和社区资源都很丰富对中文用户尤其友好django-unfold风格更贴近现代后台框架的审美主题色、侧边栏、卡片的样式都做得很细致。它们都在保留原生Admin全部功能的前提下做UI层的美化安装方式基本就是pip install然后往INSTALLED_APPS里注册几乎不用改已有代码。需要提醒的是这类皮肤工具偶尔会跟新版Admin API有兼容抖动升级前先看看项目进度。7. 部署前的检查清单与我的实战经验7.1 DEBUGFalse之后的三个坑本地开发跑得欢一台生产环境就白屏几乎是每个Django新手都要经历的。最大的坑就是DEBUGFalse。DEBUGFalse意味着Django不再处理静态文件也不再显示详细的错误页。如果你的页面加载后没有任何样式多半是静态文件配置问题。解决办法是安装whitenoise或配置Nginx托管静态文件目录然后执行python manage.py collectstatic它会把所有app下的静态文件、Admin自带的样式统一收集到STATIC_ROOT指定的目录。第二个坑是ALLOWED_HOSTS。线上环境必须改成你的域名比如ALLOWED_HOSTS [www.example.com]否则Django会拦下所有请求。第三个坑是SECRET_KEY。开发文件里的密钥绝不能直接用在生产环境应该从环境变量读取import os SECRET_KEY os.environ.get(DJANGO_SECRET_KEY, fallback-dev-key)这三个坑你提前踩明白上线当晚就能睡个好觉。7.2 从SQLite到PostgreSQL数据库切换实操开发期SQLite是真香一个文件全部搞定。但上了生产环境我还是建议换PostgreSQL。并发写多、数据量大时SQLite经常出现锁库问题PostgreSQL则稳健得多。切换过程不复杂。先装驱动pip install psycopg2-binary再改settingsDATABASES { default: { ENGINE: django.db.backends.postgresql, NAME: blogdb, USER: bloguser, PASSWORD: 你的密码, HOST: 127.0.0.1, PORT: 5432, } }数据迁移的方式有两种如果是新站直接migrate生成全部表如果是老站可以用dumpdata导出SQLite里的数据再在PostgreSQL上loaddata导入。这期间要注意中文内容的编码问题dumpdata时建议加上--indent 2方便排查导入前让两边模型保持一致。7.3 Django项目实战新手的最后几条忠告django项目实战新手也是热搜词常客说明想走这条路的人不少。结合我带过的项目和自己的踩坑史给几条实在的建议。第一功能一定做减法。第一版博客系统只要能发布文章、能评论、能搜索就算成功。什么个性化推荐、积分系统、多主题切换统统先放下做出来的东西要能上线才叫真本事。第二优先用Django自带的东西。认证、Session、Admin、ORM、模板这些是框架的核心资产别绕过它们重复造轮子。先把自带轮子用熟练再去谈定制。第三模型字段想清楚再写。数据库一旦积累真实数据后面加字段、改类型都要小心翼翼。初期宁可多想几种情况给字段老老实实设置default也别上线后频繁改表。第四把官方文档当字典用。遇到报错先看报错信息里面有哪个关键词再去文档里搜。比直接复制网上的零散代码可靠得多。最后说几句实际体会这篇博客系统教程的每段代码都是我至少做过一轮、起码有一个曾经写歪过的版本才有底气写出来的。第一次做博客时我也曾纠结要不要上Vue Django REST Framework的前后端分离后来才明白Django的模板系统加上ORM服务端渲染一个人完全撑得起一个内容型网站。前后端分离解决的是多人协作、多端复用的问题大部分个人博客根本没到那个规模。如果看完你想动手做点什么我建议就从这个博客开始的完整闭环做起建模型、写视图、调模板、补认证、加搜索、然后部署上线。等整套流程走完你对Django全栈开发的底气一定会大大不同。过程中遇到任何问题优先看报错堆栈里的文件路径再回到官方文档里定位对应的概念模块这条路径我走了五年一直有效。
返回列表