Django 是 Python 生态中最常用的 Web 框架之一,很多初学者在看完官方文档后仍然不清楚如何把项目跑起来。本文以官方 demo 为主线,从安装、创建项目、编写视图、配置数据库、管理后台,一直到自动化测试,完整演示一个投票应用(polls)的开发过程。
一、安装 Django 并创建项目
建议使用 Python 3.8 及以上版本,安装命令很简单:
进入工作目录后,用 django-admin 创建项目:
- django-admin startproject mysite
复制代码
此时会生成如下结构:
- mysite/
- manage.py
- mysite/
- __init__.py
- settings.py
- urls.py
- asgi.py
- wsgi.py
复制代码
其中 manage.py 是项目管理入口,mysite/settings.py 负责全局配置,urls.py 是根路由。
二、启动开发服务器
进入项目目录:
- python manage.py runserver
复制代码
浏览器访问 http://127.0.0.1:8000/ 即可看到 Django 的欢迎页。这个开发服务器自带热加载,改完代码保存后会自动重启。
三、创建应用并实现第一个视图
项目和应用是两个概念:一个项目可以包含多个应用。这里创建名为 polls 的应用:
- python manage.py startapp polls
复制代码
生成目录中最重要的两个文件是 views.py 和 models.py。
先写一个最简单的视图,编辑 polls/views.py:
- from django.http import HttpResponse
- def index(request):
- return HttpResponse("Hello, world. You're at the polls index.")
复制代码
光有视图还不够,必须配置路由。在 polls 目录下新建 urls.py:
- from django.urls import path
- from . import views
- urlpatterns = [
- path('', views.index, name='index'),
- ]
复制代码
然后在项目根路由 mysite/urls.py 中挂载 poll 应用的路由:
- from django.contrib import admin
- from django.urls import include, path
- urlpatterns = [
- path('polls/', include('polls.urls')),
- path('admin/', admin.site.urls),
- ]
复制代码
重启开发服务器后,访问 http://127.0.0.1:8000/polls/ 就能看到刚才返回的字符串。
四、配置数据库并创建模型
Django 默认使用 SQLite,适合开发和学习。在迁移前先执行初始化操作:
migrate 会根据已安装的应用创建数据表。接下来定义两个模型:Question(问题)和 Choice(选项)。
编辑 polls/models.py:
- 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)
复制代码
Question 包含问题文本和发布日期;Choice 通过外键关联到 Question,并记录选项文本和票数。on_delete=models.CASCADE 表示当问题被删除时,其下的选项也会被级联删除。
要在后台管理该模型,还需要打开 polls/admin.py 注册:
- from django.contrib import admin
- from .models import Question
- admin.site.register(Question)
复制代码
同时在 settings.py 的 INSTALLED_APPS 中加入 'polls.apps.PollsConfig',然后生成并应用迁移:
- python manage.py makemigrations polls
- python manage.py migrate
复制代码
django-admin 创建应用时在 apps.py 里生成了 PollsConfig 类,所以这样配置即可。
五、使用 Django Shell 调试模型
Django 提供了一个交互式环境,方便验证模型逻辑。启动 shell:
在 shell 中可以用 Python 语法操作数据库。更重要的是,Django 官方建议把系统的当前时间统一使用 timezone 获取,而不是裸用 datetime.datetime.now()。所以在相关代码中需要导入:
- import datetime
- from django.utils import timezone
复制代码
这样可以避免时区不一致导致的日期判断错误。
六、创建后台管理账号
Django 自带一个强大的 admin 后台。先创建超级用户:
- python manage.py createsuperuser
复制代码
按提示输入用户名、邮箱和密码。然后访问 http://127.0.0.1:8000/admin/ 登录,就可以看到 Question 的管理入口。
七、为视图增加模板
目前 index 视图只是返回字符串。真实环境中,我们通常会使用模板。创建一个模板目录:
- polls/templates/polls/index.html
复制代码
Django 的 TEMPLATES 配置默认开启 APP_DIRS=True,因此它会在每个已安装应用的 templates 子目录下查找模板。更新 polls/views.py,让视图读取数据库中最新的 5 条问题:
- from django.http import HttpResponse
- from .models import Question
- def index(request):
- latest_question_list = Question.objects.order_by('-pub_date')[:5]
- output = ', '.join([q.question_text for q in latest_question_list])
- return HttpResponse(output)
复制代码
然后使用 render 简化模板渲染代码,并处理列表为空的情况。
八、从展示逻辑改为通用视图
官方教程建议在业务逻辑成熟后切换到通用视图,可以大幅减少重复代码。需要做三步:调整 URLconf、删除旧的 index/detail 视图、引入基于类的 ListView/DetailView。通用视图默认使用“应用名/模型名_list.html”和“应用名/模型名_detail.html”作为模板,同时通过 context_object_name 指定模板变量名,例如:
- class IndexView(generic.ListView):
- template_name = 'polls/index.html'
- context_object_name = 'latest_question_list'
- def get_queryset(self):
- return Question.objects.order_by('-pub_date')[:5]
复制代码
这种写法在大型项目中更容易维护。
九、编写自动化测试
Django 的测试框架基于 unittest,测试文件放在应用的 tests.py 中。
先发现一个 Bug:Question.was_published_recently() 在 pub_date 为未来时间时也会返回 True。我们编写测试来暴露它:
- import datetime
- from django.test import TestCase
- from django.utils import timezone
- from .models import Question
- class QuestionModelTests(TestCase):
- def test_was_published_recently_with_future_question(self):
- future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
- self.assertIs(future_question.was_published_recently(), False)
复制代码
运行测试:
- python manage.py test polls
复制代码
此时测试会失败,因为当前方法的实现不满足未来时间返回 False 的要求。
修复方法很简单:在 was_published_recently() 中增加时间范围判断:
- def was_published_recently(self):
- now = timezone.now()
- return now - datetime.timedelta(days=1) <= self.pub_date <= now
复制代码
为了更全面地覆盖边界条件,还应该增加“一天内发布返回 True”和“超过一天返回 False”的测试。
十、视图也要测试
某些用户的浏览器时间设置可能与服务器不同,Django 的测试客户端可以直接模拟请求。例如验证未来发布的问题不出现在索引页:
- def test_future_question_not_in_index(self):
- future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
- response = self.client.get('/polls/')
- self.assertNotContains(response, future_question.question_text)
复制代码
这种测试能防止后续重构时回归。
十一、自定义界面和样式
Django 的静态文件查找机制与模板类似。在 polls 应用下创建:
- polls/static/polls/style.css
复制代码
在模板中通过 {% load static %} 和 {% static 'polls/style.css' %} 引入。背景图可以放在 polls/static/polls/images/ 目录,然后在 CSS 中指定路径。
十二、自定义后台表单和关联对象
默认后台只显示 Question 本身的字段,无法同时编辑关联的 Choice。可以在 admin.py 中使用 TabularInline:
- from django.contrib import admin
- from .models import Question, Choice
- class ChoiceInline(admin.TabularInline):
- model = Choice
- extra = 3
- class QuestionAdmin(admin.ModelAdmin):
- inlines = [ChoiceInline]
- admin.site.register(Question, QuestionAdmin)
复制代码
这样管理页面就能同时维护问题和选项,减少反复切换页面的麻烦。
总结
本文从一个空目录开始,完成了 Django 项目的搭建、模型定义、数据库迁移、后台注册、模板渲染、通用视图改造以及自动化测试。其中最值得记住的是:视图尽量只做调度,业务逻辑放在模型层;日期时间必须用 timezone;每个 bug 都应该先写一个失败的测试再修复。这套流程不仅是官方 demo 的重复,也是正式开发的基础范式。 |