Django初学教程(一)

创建项目

  1. 创建虚拟环境
1
2
3
conda create -n testDjango python=3.8
conda activate testDjango
pip install Django # 注意这里Django首字母大写
  1. 创建项目
1
2
cd D:\PythonCode
django-admin startproject mysite

创建成功的项目结构为:

1
2
3
4
5
6
7
8
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py

启动服务器:

1
2
cd mysite
python manage.py runserver

创建应用

项目=(一个及以上的)应用程序 + 配置

创建应用

1
2
# 项目名称为"polls"
python manage.py startapp polls

创建成功的应用结构为:

1
2
3
4
5
6
7
8
9
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py

创建首页

1
2
3
4
5
6
# 修改polls/views.py,创建index view

from django.http import HttpResponse

def index(request):
return HttpResponse("Hello, world. You're at the polls index.")

配置url

应用的url配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
# 新增polls/urls.py, 用于配置应用"polls"下的url

from django.urls import path

from . import views

# 设置应用程序命名空间
# 在真正的 Django 项目中,可能有五个、十个、二十个或更多应用程序。Django 如何区分它们之间的 URL 名称?——即将命名空间app_name = "polls"添加到 URLconf 中

app_name = "polls"
urlpatterns = [
path("", views.index, name="index"),
]

项目的url配置文件

1
2
3
4
5
6
7
8
9
# 修改mysite/urls.py,将应用"polls"下的urls.py引入

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path("polls/", include("polls.urls")),
path("admin/", admin.site.urls),
]

启动服务器:

1
python manage.py runserver

启动服务器后访问链接:http://127.0.0.1:8000/polls/,即可访问到index view

连接Database

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在项目的settings.py(即mysite/settings.py)中修改数据库配置

# 修改数据库配置——更改为mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_test',
"USER": "root",
"PASSWORD": "123456xjy",
"HOST": "127.0.0.1",
"PORT": "3306",
}
}
1
2
3
# 首次连接mysql数据库需要在虚拟环境导入以下2个包
pip install pymysql
pip install mysqlclient
1
2
# 执行数据迁移——将"mysite/settings.py"中INSTALLED_APPS对应的数据表都创建出来(创建到上述的"db_test"数据库中)
python manage.py migrate

建立Model

步骤

  • Change your models (in models.py).
  • Run python manage.py makemigrationsto create migrations for those changes
  • Run python manage.py migrateto apply those changes to the database.

Change your models

1
2
3
4
5
6
7
8
9
10
11
12
13
# 修改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)

make migrations

  1. 将应用"polls"放到项目的setting.py(即mysite/settings.py)的INSTALLED_APPS中
1
2
3
4
5
6
7
8
9
10
11
# 修改mysite/settings.py,增加一行"polls.apps.PollsConfig",

INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
  1. make migrations
1
python manage.py makemigrations polls
  1. migrate
1
2
# 运行以下代码,即可将models.py中新创建的类Question和类Choice,在数据库中创建出对应的数据表
python manage.py migrate
  1. 进入Python环境
1
python manage.py shell

We’re using this instead of simply typing “python”, because manage.py sets the DJANGO_SETTINGS_MODULE environment variable, which gives Django the Python import path to your mysite/settings.py file.

管理后台

  1. 创建超级管理员
1
python manage.py createsuperuser
  1. 运行服务器
1
python manage.py runserver
  1. 将自定义的类注册到管理后台
1
2
3
4
5
6
# 修改polls/admin.py,将新注册的类Question注册到管理后台

from django.contrib import admin
from .models import Question

admin.site.register(Question)

增加Views

  1. 新增视图

每一个View就干两件事中的一件:要么返回一个HttpResponse,要么返回一个Exception(如Http404)

1
2
3
4
5
6
7
8
9
10
11
12
# 在polls/views.py新增以下函数(视图)
# 以下均为虚拟实现

def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)

def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
  1. 配置应用url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 将新增的view写入pools/urls.py

from django.urls import path

from . import views

urlpatterns = [
# ex: /polls/
path("", views.index, name="index"),
# ex: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
# ex: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
# ex: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]
  1. 用户访问视图的运行流程

请求页面"/polls/6/"=>加载mysite.urls=>找到变量"polls/"命名的urlpatterns,即path("polls/", include("polls.urls"))=>去掉"polls/",剩余"6/"=>把剩余的"6/"发送给"polls.urls" URLconf=>匹配到了path("<int:question_id>/", views.detail, name="detail")=>导致调用了detail() 视图(views.py中的detail()),具体调用如detail(request=<HttpRequest object>, question_id=34)

修改Views

index view

上述增加视图中的视图使用了虚拟实现,并没有从数据库中读取记录,或完成其他有实际意义的任务,因此在这一板块将编写实际执行某些操作的视图。

  1. 修改视图(index view)

法1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# polls/views.py
# 修改index view (index函数),使用模板(利用HttpResponse和loader),读取数据库数据
# 加载调用的模板 polls/index.html并向其传递context。context是将模板变量名称映射到 Python 对象的字典。
from django.http import HttpResponse
from django.template import loader

from .models import Question

def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
template = loader.get_template("polls/index.html")
context = {
"latest_question_list": latest_question_list,
}
return HttpResponse(template.render(context, request))

法2:

利用render()函数代替HttpResponse和loader,简化代码

render()函数第一个参数是请求对象,第二个参数是模板名称,第三个参数是可选的字典。它返回一个HttpResponse对象,这是一个使用给定context的模板对象。

1
2
3
4
5
6
7
8
9
10
11
# polls/views.py

from django.shortcuts import render

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
context = {"latest_question_list": latest_question_list}
return render(request, "polls/index.html", context)
  1. 创建模板(index.html)

如果页面的设计硬编码在视图中,那么当我们想要更改页面的外观时,必须编辑此 Python 代码(即views.py中的函数)。因此我们使用Django的模板系统,通过创建模板,使得页面设计与Python代码分离。

在应用的目录下创建templates目录(即polls/templates/),Django会默认在这个目录下寻找模板。

创建好模板文件后的目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
# 这里还在templates目录下创建了一个polls子目录,在子目录下才放置了模板文件index.html
# 这里新建的polls子目录起到划分命名空间的作用。因为如果在不同的应用程序中具有相同名称的模板,Django 将无法区分它们,所以需要设置命名空间。

polls/
__init__.py
admin.py
models.py
views.py
templates
polls
index.html

index.html的文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
# polls/templates/polls/index.html

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
  1. 移除模板文件中的硬编码URL
1
2
3
4
5
6
7
8
9
10
11
# 修改前
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

# 修改后
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

# 修改原因:在polls/urls.py中,views.py的detail()函数路径被注册为
path("<int:question_id>/", views.detail, name="detail"),其中name属性为"detail"

# 继续修改:在polls/urls.py中设置应用程序命名空间(app_name = "polls")后,继续修改为指向命名空间的详细视图
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

detail view

  1. 修改视图(detail view)

使用get方法特别容易产生404错误,因此产生了一个快捷方式,即使用get_object_or_404()来进行查询。get_object_or_404()第一个参数是a Django model,第二个参数是任意数量的关键词参数。如果查询对象存在,则返回该模型对象;如果对象不存在,则返回Http404。

1
2
3
4
5
6
7
8
9
10
# polls/views.py

from django.shortcuts import get_object_or_404, render

from .models import Question


def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
  1. 创建模板(detail.html)
1
2
3
4
5
6
7
8
9
10
11
12
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
  1. 2中的vote()函数还需要具体实现

后续内容可以参考官方文档https://docs.djangoproject.com/en/5.0/intro/tutorial04/