Contents

DjangoGirls

参考资料

原始笔记中的参考链接指向了错误的页面,已修正为 DjangoGirls 教程实际地址

一、环境搭建与项目初始化

1.1 Python 虚拟环境

需要先准备好 MySQL 环境

安装 pip 和 venv:

1
2
sudo apt-get update
sudo apt install python3-pip python3-venv

创建虚拟环境:

1
python3 -m venv learningdjango

激活虚拟环境:

  • Windows:切换到 learningdjango\Scripts 目录,执行 activate.batActivate.ps1
  • Linux:进入 learningdjango/bin 目录,执行 source ./activate

在 VSCode 中选择解释器:按下 Ctrl + Shift + P,输入 interpreter 选择刚创建的虚拟环境对应的 Python 解释器(需先安装 Python 插件)

1.2 安装 Django 与依赖

安装 Django(指定 3.2 版本):

1
pip install Django==3.2 -i https://mirrors.aliyun.com/pypi/simple

Linux 环境下未指定版本时,安装了 Django-5.1.5、asgiref-3.8.1、sqlparse-0.5.3

安装 PyMySQL:

1
pip install PyMySQL -i https://mirrors.aliyun.com/pypi/simple

清除 pip 缓存:

1
pip cache purge

1.3 创建项目与初始配置

切换到 learningdjango 目录下,新建项目:

1
django-admin startproject mysite

修改 mysite/settings.py,需要调整以下配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysite',
        'USER': 'root',    # 改成自己的 MySQL 账号密码
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': 3306,
    }
}

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'

打开 mysite/__init__.py,添加 PyMySQL 作为 MySQLdb 的替代:

1
2
3
import pymysql

pymysql.install_as_MySQLdb()

1.4 数据库迁移与启动服务

1
2
python manage.py migrate
python manage.py runserver 0:8000

二、模型层(Model)

2.1 模型概念

Django 里的模型是一种特殊的对象,它保存在数据库中,可以将其类比为电子表格中的列(字段)和行(数据)。

2.2 创建应用与注册

learningdjango/mysite 目录下,执行:

1
python manage.py startapp blog

mysite/settings.pyINSTALLED_APPS 中添加 'blog'

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
)

2.3 定义 Post 模型

blog/models.py 中编写:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from django.conf import settings
from django.db import models
from django.utils import timezone


class Post(models.Model):
    author = models.ForeignKey(
                settings.AUTH_USER_MODEL,
                on_delete=models.CASCADE
            )
    title = models.CharField(
                max_length=200
            )
    text = models.TextField()
    created_date = models.DateTimeField(
                        default=timezone.now
                    )
    published_date = models.DateTimeField(
                        blank=True, null=True
                    )

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title    # 得到文章标题的文本

2.4 执行迁移

将新模型添加到数据库:

1
2
python manage.py makemigrations blog
python manage.py migrate blog

2.5 Django ORM 与 QuerySets

Django ORM 实现使用操作对象的方式来操作数据库中的数据,为了让不懂 SQL 语句的人也能通过 Python 面向对象的知识轻松操作数据库。

进入 Django Shell:

1
python manage.py shell

在这个 Django 的交互式控制台中,就像 Python 提示符,但有一些额外神奇的 Django 特性。你当然也可以在这里使用所有的 Python 命令。尝试以下语句:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from blog.models import Post
Post.objects.all()                              # 查询所有 Post 对象
from django.contrib.auth.models import User
User.objects.all()                              # 查看有哪些用户
me = User.objects.get(username='前面创建的超级用户的名字')
Post.objects.create(author=me, title='Sample title', text='Test')  # 创建新 Post
Post.objects.all()                              # 确认创建成功
Post.objects.filter(title__contains='title')    # 筛选:Django ORM 使用双下划线分隔字段名称("title")和操作/筛选器("contains")
post = Post.objects.get(title="Sample title")
post.publish()                                  # 发布文章
Post.objects.order_by('created_date')           # 按创建日期排序,反向排序用 '-created_date'
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')  # 链式:筛选并排序
exit()

三、Admin 后台管理

打开 blog/admin.py,注册 Post 模型:

1
2
3
4
5
from django.contrib import admin
from .models import Post


admin.site.register(Post)    # 注册前面编写的blog模型中的Post类

创建掌控整个网站的超级用户:

1
python manage.py createsuperuser

然后输入用户名(英文小写,不含空格)、邮箱和密码。

启动服务器并访问后台:

1
python manage.py runserver

浏览器打开 http://127.0.0.1:8000/admin/ ,用超级用户的用户名和密码登录。在 Blog 的 Posts 页面多复制粘贴几篇文章或博客,后面展示的时候会用到。

四、路由层(URL)

4.1 项目级 URL 配置

配置 mysite/urls.py

1
2
3
4
5
6
7
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'', include('blog.urls')),
]

注意:django.conf.urls.url 在 Django 4.0 中已移除,若使用 Django 4.0+,需改用 django.urls.pathre_path

4.2 应用级 URL 配置

配置 blog/urls.py

1
2
3
4
5
6
7
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
    # 如果有人访问 http://127.0.0.1:8000 地址,views.post_list 是这个请求该去到的地方
]

后续随着功能扩展,blog/urls.py 完整的 URL 模式如下:

1
2
3
4
5
6
7
8
9
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'),
    url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'),
]

当你访问 http://127.0.0.1:8000/post/5/ 时,Django 会识别名为 post_detail 的视图,并传递 pk=5 到该视图。

五、视图层(View)

View 是存放应用逻辑的地方。它将从 Models 中获取数据,并将它传递给 Templates。

5.1 基础视图

打开 blog/views.py

1
2
3
4
5
6
from django.shortcuts import render

# Create your views here.
def post_list(request):
    return render(request, 'blog/post_list.html', {})
    # 它接受 request 参数作为输入,并返回用 render 方法渲染模板 blog/post_list.html 而得到的结果

5.2 传递动态数据的视图

修改 blog/views.py,从数据库获取已发布的文章并传递到模板:

1
2
3
4
5
6
7
8
from django.shortcuts import render
from django.utils import timezone
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})
    # 传递 posts 查询集到模板中,{} 是一些模板要使用的东西

5.3 文章详情视图

1
2
3
4
5
from django.shortcuts import render, get_object_or_404

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

5.4 表单相关视图

新建文章视图:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from .models import Post
from .forms import PostForm

def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)    # 暂时不保存,下面还要添加 author 和发布日期
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            # 创建完新帖子就转去 post_detail 页面
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

编辑文章视图:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def post_edit(request, pk):
    # 注意从 urls 里传递了一个额外的 pk 参数
    post = get_object_or_404(Post, pk=pk)
    # 预保存 blog
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        # 仅编辑 blog
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

六、模板层(Template)

6.1 基础模板

模板保存在 blog/templates/blog/ 目录中。

初始的 post_list.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<html>
  <head>
    <title>Django Girls blog</title>
  </head>
  <body>
    <div>
      <h1><a href="">My Blog</a></h1>
    </div>

    <div>
      <p>published: 14.06.2014, 12:14</p>
      <h2><a href="">My first post</a></h2>
      <p>
        Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis
        vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce
        dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut
        fermentum massa justo sit amet risus.
      </p>
    </div>

    <div>
      <p>published: 14.06.2014, 12:14</p>
      <h2><a href="">My second post</a></h2>
      <p>
        Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis
        vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce
        dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut f.
      </p>
    </div>
  </body>
</html>

6.2 动态数据渲染

使用 Django 模板标签,将数据库中的数据渲染到页面。blog/templates/blog/post_list.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<div>
  <h1><a href="/">Django Girls Blog</a></h1>
</div>

<!-- 使用 for 循环,遍历 posts 对象列表中的每个对象 -->
{% for post in posts %}
<div>
  <p>published: {{ post.published_date }}</p>
  <h1><a href="">{{ post.title }}</a></h1>
  <p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}

6.3 模板扩展(base.html)

blog/templates/blog/ 下创建 base.html 作为基础模板,子模板通过 {% extends %} 继承它,并通过 {% block content %} 填充各自的内容。

base.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{% load static %}
<html>
  <head>
    <title>Django Girls blog</title>
    <!-- Bootstrap 是最流行的 HTML 和 CSS 框架之一,可以用来开发炫酷的网站,起初由 Twitter 的程序员编写,现在由来自世界各地的志愿者维护 -->
    <link
      rel="stylesheet"
      href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
    />
    <link
      rel="stylesheet"
      href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"
    />
    <link
      href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"
      rel="stylesheet"
      type="text/css"
    />
    <link rel="stylesheet" href="{% static 'css/blog.css' %}" />
  </head>
  <body>
    <div class="page-header">
      {% if user.is_authenticated %}
      <a href="{% url 'post_new' %}" class="top-menu"
        ><span class="glyphicon glyphicon-plus"></span
      ></a>
      <!-- 使新建文章链接仅在以管理者身份登录的用户访问时显示 -->
      {% endif %}
      <h1><a href="/">Django Girls Blog</a></h1>
    </div>

    <div class="content container">
      <div class="row">
        <div class="col-md-8">{% block content %} {% endblock %}</div>
      </div>
    </div>
  </body>
</html>

注意:原教程使用 {% load staticfiles %},该标签在 Django 3.0 中已弃用,应改用 {% load static %}

post_list.html 改为继承 base.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{% extends 'blog/base.html' %}
<!-- 直接使用 base 文件的模板 -->

{% block content %} {% for post in posts %}
<div class="post">
  <div class="date">{{ post.published_date }}</div>
  <h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1>
  <p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %} {% endblock %}

6.4 文章详情模板

blog/templates/blog/ 下创建 post_detail.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{% extends 'blog/base.html' %} {% block content %}
<div class="post">
  {% if post.published_date %}
  <div class="date">{{ post.published_date }}</div>
  {% endif %}
  <!-- 添加一个跳转到编辑页面的链接 -->
  <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"
    ><span class="glyphicon glyphicon-pencil"></span
  ></a>
  <h1>{{ post.title }}</h1>
  <p>{{ post.text|linebreaksbr }}</p>
</div>
{% endblock %}

七、表单处理

7.1 创建表单类

blog/ 目录下创建 forms.py

1
2
3
4
5
6
7
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'text',)

7.2 文章编辑模板

blog/templates/blog/ 下创建 post_edit.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{% extends 'blog/base.html' %} {% block content %}
<h1>New post</h1>
<form method="POST" class="post-form">
  {% csrf_token %}
  <!-- 要添加表单只需要加入下面这个语句 -->
  <!-- 注意防止 csrf -->
  {{ form.as_p }}
  <!-- 设置保存按钮 -->
  <button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}

八、静态资源与前端美化

8.1 CSS 样式

blog/static/css/ 目录下创建 blog.css

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
.page-header {
  background-color: #ff9400;
  margin-top: 0;
  padding: 20px 20px 20px 40px;
}

.page-header h1,
.page-header h1 a,
.page-header h1 a:visited,
.page-header h1 a:active {
  color: #ffffff;
  font-size: 36pt;
  text-decoration: none;
}

.content {
  margin-left: 40px;
}

h1,
h2,
h3,
h4 {
  font-family: 'Lobster', cursive;
}

.date {
  float: right;
  color: #828282;
}

.save {
  float: right;
}

.post-form textarea,
.post-form input {
  width: 100%;
}

.top-menu,
.top-menu:hover,
.top-menu:visited {
  color: #ffffff;
  float: right;
  font-size: 26pt;
  margin-right: 20px;
}

.post {
  margin-bottom: 70px;
}

.post h1 a,
.post h1 a:visited {
  color: #000000;
}

8.2 Bootstrap 集成

base.html 中引入 Bootstrap(见 6.3 节模板代码),Bootstrap 是最流行的 HTML 和 CSS 框架之一,起初由 Twitter 的程序员编写,现在由来自世界各地的志愿者维护。

九、部署与版本控制

若只是熟悉 Django 开发流程,可以跳过此节

9.1 Git 初始化与配置

打开 Git Bash,切换到 learningdjango/ 路径下:

1
2
3
git init
git config --global user.name "你想用的名字"
git config --global user.email 你的邮箱

Git 默认会追踪目录下所有文件和文件夹的更改。创建 .gitignore 文件来忽略无需追踪的文件:

1
2
3
4
5
*.pyc
__pycache__
myvenv
db.sqlite3
.DS_Store

9.2 推送到 GitHub

添加、提交文件:

1
2
3
git status
git add --all .
git commit -m "本次提交内容的注释"

在 GitHub 上新建仓库(如 my-first-blog),保持 README 不生成,.gitignore 和 License 也设置为无。然后将本地仓库与远程仓库关联:

1
2
git remote add origin https://github.com/yjjyjya/my-first-blog.git
git push -u origin master

之后需要输入账号密码,代码就会被 push 到 GitHub 上面了。

日常更新代码的推送流程:

1
2
3
4
5
git status
git add --all .
git status
git commit -m "......"
git push

9.3 常见问题

若 push 等待时间过长或报错,可尝试取消代理配置:

1
2
git config --global --unset http.proxy
git config --global --unset https.proxy

拓展与后续学习建议

  • Django 版本迁移:本笔记基于 Django 3.2,如需升级到 Django 4.x/5.x,需注意 django.conf.urls.url 已移除,应改用 path()re_path(){% load staticfiles %} 改为 {% load static %}
  • Django REST Framework:学习构建 RESTful API,为前后端分离架构打下基础
  • 基于类的视图(CBV):用类视图替代函数视图,减少重复代码,更适合复杂业务逻辑
  • 用户认证系统:深入学习 Django 自带的认证系统(注册、登录、权限管理),以及第三方库如 django-allauth
  • 数据库进阶:了解 Django 的数据库迁移机制、索引优化、QuerySet 性能调优(select_relatedprefetch_related
  • 测试:学习 Django 的测试框架,编写单元测试和集成测试,保障代码质量
  • 部署实践:了解 Nginx + Gunicorn/uWSGI 部署方案、Docker 容器化部署,以及云平台(如 PythonAnywhere)的部署方式
  • 官方文档Django 官方文档 是最权威的参考来源,建议养成查阅习惯

优化要点总结

优化维度 具体操作
事实修正 修正了错误的参考链接;补充了 redirect 导入;标注了 {% load staticfiles %}url() 的弃用/移除信息
逻辑重构 按 Django MVT 架构重新组织为九大章节:环境搭建 → 模型 → Admin → URL → 视图 → 模板 → 表单 → 前端 → 部署,从主干到分支、从基础到深入
归并去重 将分散在多处的同一文件修改合并到一处(如 views.py 的 4 次修改合并为一个完整的视图文件;base.html 的 3 次迭代合并为最终版本)
内容保留 原笔记中的所有知识点、代码注释、数据(如 Linux 下安装的版本号)、提示说明均已保留
排版规范 移除了章节标题的粗体标记,全文加粗次数极少;未使用 Emoji
增值补充 末尾新增"拓展与后续学习建议"独立章节,与原有内容严格分离