hzy1721

安装

https://docs.djangoproject.com/en/3.1/intro/install/

https://docs.djangoproject.com/en/3.1/faq/install/#faq-python-version-support

https://docs.djangoproject.com/en/3.1/topics/install/#database-installation

https://docs.djangoproject.com/en/3.1/ref/databases/#mysql-db-api-drivers

https://pypi.org/project/mysqlclient/

https://docs.djangoproject.com/en/3.1/ref/databases/#mysql-notes

https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-DATABASES

https://docs.djangoproject.com/en/3.1/topics/install/#installing-official-release

Django 最新的 3.1 版本支持 Python 3.6 ~ 3.9,所以只要 Python 的版本不是太旧,都可以使用。

Django 等 Python 框架的一个特点就是默认使用轻量数据库 SQLite,方便轻量使用和应用测试。

当然,我们最熟悉和常用的还是 MySQL,Django 也提供了支持 (>= 5.6,目前最新版是 8.0)。

在使用之前需要安装 MySQL Python 驱动。Django 支持两种:mysqlclient 和 MySQL Connector/Python,前者是官方推荐使用的,所以这里安装 mysqlclient。

pip3 install mysqlclient

然后使用 pip 安装官方发布的最新版本:

pip3 install Django

最好使用 venv 创建一个项目专用的环境,这里以测试和学习为主,所以安装到系统环境。

验证是否安装成功以及查看版本:

▶ python3 -m django --version
3.1.3

到这里就完成了安装。

基本使用

https://docs.djangoproject.com/en/3.1/intro/tutorial01/

官方的第一个教程是写一个投票应用,包括两部分:供人们查看投票和进行投票的公开站点、增删改投票的管理员站点。

创建项目 mysite

首先使用 django-admin 命令创建一个 Django 项目:

django-admin startproject mysite

会自动生成以下文件:

▶ tree mysite
mysite
├── manage.py
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 6 files
  • 最外层的 mysite 文件夹包含了整个项目,与创建时指定的项目名相同,但是可以随意修改。
  • manage.py 是 Django 提供的一个实用工具,用来管理 Django 项目。
  • 内层的 mysite 文件夹是一个 Python 包,包含了真正的项目文件。
  • __init__.py 是Python 包的标志。
  • settings.py 是 Django 项目的配置文件。
  • urls.py 是 Django 项目的路由文件。
  • asgi.py 用于以 ASGI 方式部署,开发时用不到。
  • wsgi.py 用于以 WSGI 方式部署,开发时用不到。

使用 manage.py 启动本地的开发服务器:

▶ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run \'python manage.py migrate\' to apply them.
April 05, 2021 - 09:28:43
Django version 3.1.3, using settings \'mysite.settings\'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

可以在 runserver 后面指定 IP 和端口号,比如:

python3 manage.py runserver 8080
python3 manage.py runserver 0:8000

至此一个项目就初始化好了,接下来就是应用相关的开发工作。

创建应用 polls

首先要明确两个概念:project 和 app。之前我们用 startproject 创建了一个名为 mysite 的 project,一个 project 由若干 app 和一些配置组成,而一个 app 是具体用来做一些事情的代码集合 (这里是一个 Python 包),当然一个 app 也可以位于多个 project 中。

Django 中的 project 和 app 都遵循特定的目录结构,这些结构可以使用 manage.py 来初始化,我们已经初始化好了 project 的结构,接下来初始化第一个 app —— polls (公开站点) 的目录结构:

python3 manage.py startapp polls

当前的项目结构如下:

▶ ls
db.sqlite3 manage.py  mysite     polls

▶ tree polls
polls
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

然后配置 polls 的第一个页面,在 polls/views.py 文件中加入如下语句:

from django.http import HttpResponse


def index(request):
    return HttpResponse(\'Polls index.\')

这里配置了 polls 的主页,访问主页返回一个字符串 Polls index.

还需要把页面映射到一个路径,在 polls/urls.py 加入如下语句 (需要新建文件):

from django.urls import path
from . import views

urlpatterns = [
    path(\'\', views.index, name=\'index\')
]

然后在 mysite/urls.py 中书写如下语句,将 polls 的路由规则包含进来:

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

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

然后启动开发服务器测试一下 http://127.0.0.1:8000/polls/ 能否正常访问。

在配置路由的 urls.py 文件中会用到 path 函数,该函数接收 2 个必选参数和 2 个可选参数:

  • route: URL 字符串,不包含前缀,比如 polls/urls.py 中是空串而不是完整的 polls/,因为前缀在 mysite/urls.py 中已经配置过了。
  • view: 视图函数,当访问 route 对应的路径时会调用这个函数,第一个参数传入 HttpRequest 对象,返回 HttpResponse 对象。
  • kwargs: 可选的关键字参数,将会传入视图函数。
  • name: 可选的路由名称。

配置数据库

https://docs.djangoproject.com/en/3.1/intro/tutorial02/

https://docs.djangoproject.com/en/3.1/ref/settings/#databases

这里使用 MySQL,在 mysite/settings.py 中修改 DATABASES 字典中的 default:

DATABASES = {
    \'default\': {
        \'ENGINE\': \'django.db.backends.mysql\',
        \'NAME\': \'django\',
        \'USER\': \'root\',
        \'PASSWORD\': \'********\',
        \'HOST\': \'localhost\',
        \'PORT\': \'3306\',
        \'TIME_ZONE\': \'Asia/Shanghai\'
    }
}

填写的用户 (\'USER\') 需要有创建数据库等相关权限,这里为了方便测试,直接使用 root。

然后修改 TIME_ZONE 为中国的时区:

TIME_ZONE = \'Asia/Shanghai\'

settings.py 文件的上方有 INSTALLED_APPS,显示了当前激活的应用:

INSTALLED_APPS = [
    \'django.contrib.admin\',
    \'django.contrib.auth\',
    \'django.contrib.contenttypes\',
    \'django.contrib.sessions\',
    \'django.contrib.messages\',
    \'django.contrib.staticfiles\',
]

这些是默认包含在项目中的应用,提供了许多实用的功能,可以把不需要的应用注释或删除,这里保持默认。

由于这些应用可能需要数据库表,所以执行下面的命令来自动创建需要的表:

python3 manage.py migrate

创建并激活模型 Model

Django 中的 Model 可以理解为关系模型中的一个关系、数据库中的一个表,通过编写模型文件从而让 Django 自动创建表并处理相关的数据库问题,比如列的类型变更、增加列等。

对于 polls 应用,先创建两个模型:

  • Question: 一个投票,包含投票内容和发布时间。
  • Choice:一个选择,包含选项内容和票数,还有一个 Question 类型的外键。

polls/models.py 加入以下内容:

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)

每个模型都是 Model 的子类,模型中的每个变量都是表中的一个字段,变量名就是字段名。

这里涉及到 3 个类型:字符串 Char、日期时间 DateTime、整数 Integer,还有外键可以直接指定 Model 类型。

在 Django 自动创建相关的数据库表之前,需要先安装 polls 应用,在 INSTALLED_APPS 中加入以下内容:

INSTALLED_APPS = [
    \'polls.apps.PollsConfig\',	# 添加这一行
    \'django.contrib.admin\',
    \'django.contrib.auth\',
    \'django.contrib.contenttypes\',
    \'django.contrib.sessions\',
    \'django.contrib.messages\',
    \'django.contrib.staticfiles\',
]

然后执行以下命令更新模型:

python3 manage.py makemigrations polls

执行以下命令可以查看迁移使用的 SQL 语句 (MySQL):

python3 manage.py sqlmigrate polls 0001
--
-- Create model Question
--
CREATE TABLE `polls_question` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, 
    `question_text` varchar(200) NOT NULL, `pub_date` datetime(6) NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE `polls_choice` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, 
    `choice_text` varchar(200) NOT NULL, 
    `votes` integer NOT NULL, 
    `question_id` integer NOT NULL
);
ALTER TABLE `polls_choice` 
	ADD CONSTRAINT `polls_choice_question_id_c5b4b260_fk_polls_question_id` 
	FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`);

执行 migrate 命令来真正创建这些表:

python3 manage.py migrate

综上,更新 Django 模型可以分为 3 个步骤:

  1. 修改 models.py 文件
  2. 执行 python3 manage.py makemigrations 命令
  3. 执行 python3 manage.py migrate 命令

数据库 API

执行以下命令进入 Django Shell (其实就是设置了特定环境变量的 IPython):

python3 manage.py shell

探索数据库相关函数:

In [1]: from polls.models import Choice, Question	# 导入需要的类

In [2]: Question.objects.all()	# 查询所有Question记录,类似于select * from polls_question
Out[2]: <QuerySet []>			# 空的

In [3]: from django.utils import timezone	# 用于得到当前时间

In [4]: q = Question(question_text="What\'s new?", pub_date=timezone.now())	# 实例化一个Question对象

In [5]: q.save()	# 保存到数据库

In [6]: q.id		# 访问内存中的Question对象的id属性
Out[6]: 1

In [7]: q.question_text	# question_text属性
Out[7]: "What\'s new?"

In [8]: q.pub_date		# pub_date属性
Out[8]: datetime.datetime(2021, 4, 8, 1, 49, 19, 899861, tzinfo=<UTC>)

In [9]: q.question_text = "What\'s up?"	# 修改内存中的question_text属性

In [10]: q.save()	# 保存到数据库

In [11]: Question.objects.all()	# 查询所有记录
Out[11]: <QuerySet [<Question: Question object (1)>]>	# 目前有1条

为 Model 添加 __str__ 方法能让输出结果可读性更强,顺便添加一个自定义方法 was_published_recently

import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(\'date published\')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

重启 Shell 并探索其他数据库函数:

In [1]: from polls.models import Choice, Question

In [2]: Question.objects.all()
Out[2]: <QuerySet [<Question: What\'s up?>]>

In [3]: Question.objects.filter(id=1)	# 类似于where id = 1
Out[3]: <QuerySet [<Question: What\'s up?>]>

In [4]: Question.objects.filter(question_text__startswith=\'What\')	# 类似于like \'What%\'
Out[4]: <QuerySet [<Question: What\'s up?>]>

In [5]: from django.utils import timezone

In [6]: current_year = timezone.now().year	# 取出year部分

In [7]: Question.objects.get(pub_date__year=current_year)	# 可以方便地用两个下划线+函数名的方式得到需要的值
Out[7]: <Question: What\'s up?>

In [8]: Question.objects.get(id=2)	# 找不到会报错
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
<ipython-input-8-75091ca84516> in <module>
----> 1 Question.objects.get(id=2)

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/manager.py in manager_method(self, *args, **kwargs)
     83         def create_method(name, method):
     84             def manager_method(self, *args, **kwargs):
---> 85                 return getattr(self.get_queryset(), name)(*args, **kwargs)
     86             manager_method.__name__ = method.__name__
     87             manager_method.__doc__ = method.__doc__

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/query.py in get(self, *args, **kwargs)
    429             raise self.model.DoesNotExist(
    430                 "%s matching query does not exist." %
--> 431                 self.model._meta.object_name
    432             )
    433         raise self.model.MultipleObjectsReturned(

DoesNotExist: Question matching query does not exist.

In [9]: Question.objects.get(pk=1)	# 可以使用pk来代替主键字段名
Out[9]: <Question: What\'s up?>

In [10]: q = Question.objects.get(pk=1)	# get返回1条,failter返回多条

In [11]: q.was_published_recently()
Out[11]: True

In [12]: q = Question.objects.get(pk=1)

In [13]: q.choice_set.all()	# 直接访问关联的Choice
Out[13]: <QuerySet []>

In [14]: q.choice_set.create(choice_text=\'Not much\', votes=0)	# 类似于insert,自动添加外键
Out[14]: <Choice: Not much>

In [15]: q.choice_set.create(choice_text=\'The sky\', votes=0)
Out[15]: <Choice: The sky>

In [16]: c = q.choice_set.create(choice_text=\'Just hacking again\', votes=0)

In [17]: c.question
Out[17]: <Question: What\'s up?>

In [18]: q.choice_set.all()
Out[18]: <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

In [19]: q.choice_set.count()	# 类似于count()函数
Out[19]: 3

In [20]: Choice.objects.filter(question__pub_date__year=current_year)	# 方便地进行连接查询
Out[20]: <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

In [21]: c = q.choice_set.filter(choice_text__startswith=\'Just hacking\')

In [22]: c.delete()	# 删除
Out[22]: (1, {\'polls.Choice\': 1})

总之,Django 提供了一组自己的数据库 API,实现了多种数据库后端的 API 统一,也比 SQL 更容易使用。

管理员站点 Django Admin

很多站点都需要提供对资源进行增删改查的功能,这些功能的开发内容往往都很同质化,完全可以自动生成,所以 Django 提供了管理员站点来自动实现这些功能。

首先需要创建一个管理员用户:

▶ python3 manage.py createsuperuser
Username (leave blank to use \'hzy\'): 
Email address: hzy1721@qq.com
Password: 
Password (again): 
Superuser created successfully.

管理员站点默认是开启的,启动开发服务器后访问 /admin

默认只有 django.contrib.auth 提供的 GroupsUsers,然后在 admin.py 中注册 Question 和 Choice:

from django.contrib import admin

from .models import Question, Choice

admin.site.register(Question)
admin.site.register(Choice)

然后刷新页面就可以看到这两个模型了,Django Admin 提供了美观、方便的 GUI 来增删改查模型、查看编辑历史等。

分类:

技术点:

相关文章:

  • 2021-07-13
  • 2021-10-03
  • 2021-04-05
  • 2021-07-05
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-30
猜你喜欢
  • 2022-12-23
  • 2021-04-22
  • 2022-12-23
  • 2021-06-02
  • 2021-12-24
  • 2021-09-09
  • 2022-01-19
相关资源
相似解决方案