把时间用在思考上是最能节省时间的事情。——[美]卡曾斯
本文部分内容引用的是Django官方文档,对官方文档进行了解读和理解,对官方文档的部分注释内容进行了翻译,以方便大家的阅读和理解。
在上一篇文章里,我们学习了Django的数据库以及拓展数据库的使用以及设置项。这篇文章,我们开始学习Django的模型、API以及后台管理系统的知识。
在 Django 里写一个数据库驱动的 Web 应用的第一步是定义模型 - 也就是数据库结构设计和附加的其它元数据。关于API,进入交互式 Python 命令行,尝试一下 Django 为你创建的各种 API。
为你的员工或客户生成一个用户添加,修改和删除内容的后台是一项缺乏创造性和乏味的工作。因此,Django 全自动地根据模型创建后台界面。
Django 产生于一个公众页面和内容发布者页面完全分离的新闻类站点的开发过程中。站点管理人员使用管理系统来添加新闻、事件和体育时讯等,这些添加的内容被显示在公众页面上。Django 通过为站点管理人员创建统一的内容编辑界面解决了这个问题。管理界面不是为了网站的访问者,而是为管理者准备的。
一个模型就是单个定义你的数据的信息源。模型中包含了不可缺少的数据区域和你存储数据的行为。在模型中,通过Python类进行描述。
例如,我们现在需要创建两个模型,那么就需要两个Python类,问题 Question 和选项 Choice。Question 模型包括问题描述和发布时间。Choice 模型有两个字段,选项描述和当前得票数。每个选项属于一个问题。
#导入models的包
from django.db import models
"""
定义Python的类,如下面的代码的实例。
自定义的 Model 都必须继承自 django.db.models.Model
"""
class Question(models.Model):
question_text = models.CharField(max_length=30)
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)
Django Model 的继承与 Python 类的继承是一样的,只是 Django 要求所有自定义的 Model 都必须继承自 django.db.models.Model。在 Django 中 Model 之间有三种继承模型,它们分别是抽象基类、多表继承以及代理模型。
抽象类继承的作用是将子表中通用的字段聚合在一起,并将这些字段统一定义在抽象基类中,避免于重复定义这些字段。抽象基类的定义通过在模型的 Meta 中定义属性 abstract=True 来实现。示例如下:
from django.db import models
class AbstractBase(models.Model):
id = models.AutoField()
content = models.CharField(max_length=100)
username = models.CharField(max_length=80)
nowday = models.DateTimeField()
class Meta:
abstract = True
class SomeThing(AbstractBase):
testexams = models.CharField(max_length=50)
class SomeComment(AbstractBase):
level = models.CharField(max_length=20)
这是 Django 支持的第二种继承方式,因为每个类都是一个完整的 model,而不属于抽象基类,所以父 model 和子 Model 都会有数据库表,而且 Django 默认会给和子表和父表之间自动创建一个 OneToOneField 数据表关系,并且该字段将作为子表的主键。示例如下:
from django.db import models
class a(A):
testname=models.charFiled(max_length=255,help_text="测试")
代理模型用来给父 Model 添加一些方法或者修改其 Meta 选项,但是父 Model 的字段定义不会被修改。我们可以理解为对原父 Model 进行了 Copy,而被 Copy 出来的 Model 就叫做父 Model 的代理模型,但是这个代理模型又有其自己的特点,这相当于 Python 面向对象中的类继承与多态。
class BookExtend(Book):
"""
BOOK代理模型
"""
class Meta:
ordering=['id'] #定义Meta选项顺序排序按照id字段
proxy=True #设置代理模型
def __str__(self):
return "title:%s pub:%s price:%s" % (self.title, self.pub, self.price) #定义方法
上面的一小段用于创建模型的代码给了 Django 很多信息,通过这些信息,Django 可以:
现在,我们要回到settings.py中,修改我们的代码:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls.apps.PollsConfig',
]
现在你的 Django 项目会包含 polls 应用。接着在终端运行下面的命令:
py manage.py makemigrations polls
这条命令并不会直接执行数据库迁移的操作,而是会检测你对模型文件的修改,并且把修改的部分储存为一次 迁移。
现在,让我们看看迁移命令会执行哪些 SQL 语句。sqlmigrate 命令接收一个迁移的名称,然后返回对应的 SQL:
py manage.py sqlmigrate polls 0001
你将会看到下图的输出:
在官方文档里,重组为我们能看懂的格式,如下:
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" bigint 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")
DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
现在,再次运行 migrate 命令,在数据库里创建新定义的模型的数据表:
py manage.py migrate
此时,数据库中多了两张表,如下图:
现在,你只需要记住,改变模型需要这三步:
1、编辑 models.py 文件,改变模型。
2、运行 python manage.py makemigrations 为模型的改变生成迁移文件。
3、运行 python manage.py migrate 来应用数据库迁移。
学习至此,你可以去休息一下,或者消化或者练习一下以上的知识,更快地掌握,不至于很快地忘记你学的知识。掌握并熟练运用一种知识,终究是要勤加练习的,不能偷懒。
分界线以下的知识,本是下一篇文章的内容,为了知识的连贯性,我将它们放在了一起,大家可以自由选择是否学习或者将这里做一个分界线。
人之为学,不日进则日退。——顾炎武
首先,通过以下命令进入交互行:
py manage.py shell
执行这个命令的目的,并不是单单地想要使用python,而是我们需要根据settings.py设置 Python 包的导入路径。并且,进入到这个界面,就可以探索在命令行探索数据库,即使你不懂数据库相关的知识。怎么样,是不是很贴心。
#请在shell交互行尝试以下的命令探索
from polls.models import Choice, Question
#查询表中所有的对象
Question.objects.all()
#输出:
from django.utils import timezone
#使用命令向模型传递参数
q = Question(question_text="What's new?", pub_date=timezone.now())
#执行保存命令后,Django会执行SQL的插入语句
q.save()
#查看id
q.id
#输出:1
#查看文本
q.question_text
#输出:"What's new?"
#查看日期
q.pub_date
#输出:datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.timezone.utc)
#改变文本内容
q.question_text = "What's up?"
#执行保存后,Django会执行修改操作
q.save()
#查看输出
Question.objects.all()
#输出:]>
讲到这里,大家有没有发现一个问题,貌似
现在让我们会到models这个文件,给 Question 和 Choice 增加 str() 方法。
from django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
给模型增加 str() 方法是很重要的,这不仅仅能给你在命令行里使用带来方便,Django 自动生成的 admin 里也使用这个方法来表示对象。
让我们再为此模型添加一个自定义方法,修改models中的代码片段
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
保存这些更改并再次运行 python manage.py shell 以启动新的 Python 交互式 shell:
from polls.models import Choice, Question
Question.objects.all()
#输出:]>
Question.objects.filter(id=1)
#]>
Question.objects.filter(question_text__startswith="What")
#]>
from django.utils import timezone
current_year = timezone.now().year
Question.objects.get(pub_date__year=current_year)
#]>
我在操作这部分内容的时候,出现了下面两种错误
1、NameError: name ‘Question’ is not defined
解决方案:导入from polls.models import Choice, Question,导入对应的参数
2、Django (2006, ‘MySQL server has gone away’)
解决方案:重新启动服务器,一般都能解决。
3、执行【Question.objects.get(id=2)】
解决方案:id不存在,创建该字段或者忽略该问题。
Question.objects.get(pk=1)
#
q = Question.objects.get(pk=1)
q.was_published_recently()
#输出:True
现在我们要开始处理我们编写的模型中的第二个Python类:选项。
#给这个问题几个选项,对象,执行INSERT语句,将选择项添加到集合中
#查询id=1的问题,并存储在变量q中
q = Question.objects.get(pk=1)
#显示相关对象集中的任何选项——到目前为止还没有。
q.choice_set.all()
#输出:
#创建3个选项
q.choice_set.create(choice_text="Not much", votes=0)
#
q.choice_set.create(choice_text="The sky", votes=0)
#
c = q.choice_set.create(choice_text="Just hacking again", votes=0)
#选择对象可以通过API访问其相关的问题对象。
#确认一下选项对应的问题
c.question
#
q.choice_set.all()
#, , ]>
q.choice_set.count()
#输出:3
#查询
Choice.objects.filter(question__pub_date__year=current_year)
#, , ]>
#查询出来需要删除的选项,并存储在变量中
c = q.choice_set.filter(choice_text__startswith="Just hacking")
#执行删除操作
c.delete()
写到这里,有关Django提供的API操作就暂时讨论到这里啦。是不是很便捷,这就是Django的强大指出之一。下面让我们一起走进Django的后台管理系统,为我们更加便捷的开发工作提供便利。
为你的员工或客户生成一个用户添加,修改和删除内容的后台是一项缺乏创造性和乏味的工作。因此,Django 全自动地根据模型创建后台界面。
Django 产生于一个公众页面和内容发布者页面完全分离的新闻类站点的开发过程中。站点管理人员使用管理系统来添加新闻、事件和体育时讯等,这些添加的内容被显示在公众页面上。Django 通过为站点管理人员创建统一的内容编辑界面解决了这个问题。
管理界面不是为了网站的访问者,而是为管理者准备的。
要创建登录账号,请执行以下命令:
py manage.py createsuperuser
接着,根据提示创建用户名、电子邮件、密码、确认密码,如下图
由于我们创建的是超级管理员,所以所有的警示信息都可以忽略,直接选择y(是),直接执行即可。电子邮件如果不输入直接回车跳过即可。
Django 的管理界面默认就是启用的。让我们启动开发服务器,看看它到底是什么样的。如果开发服务器未启动,用以下命令启动它:
py manage.py runserver
1、请访问你的后台管理地址,例如:http://127.0.0.1:8888/admin/。
2、输入用户名和密码进入后台管理界面,例如admin/123456
但是我们的投票应用在哪呢?它没在索引页面里显示。只需要再做一件事:我们得告诉管理,问题 Question 对象需要一个后台接口。打开 polls/admin.py 文件,把它编辑成下面这样:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
现在我们向管理页面注册了问题 Question 类。Django 知道它应该被显示在索引页里:
点击 “Questions” 。现在看到是问题 “Questions” 对象的列表 “change list” 。这个界面会显示所有数据库里的问题 Question 对象,你可以选择一个来修改。这里现在有我们在上一部分中创建的 “What’s up?” 问题。
点击 “What’s up?” 来编辑这个问题(Question)对象:
点击右上角的历史,之后页面如下图所示:
你会看到一个列出了所有通过 Django 管理页面对当前对象进行的改变的页面,其中列出了时间戳和进行修改操作的用户名:
本文将两个课时的内容合为一篇长文章,详尽地讨论了API、模型以及后台管理系统。希望大家可以慢慢消化,认真阅读,有所收获。
下一篇文章,我们将继续深入Django,除了模型,下一篇文章我们将详尽地讲述Django的视图,请大家继续期待。
这一篇文章至此,已经写到末尾,感谢你的阅读和支持,如果允许,请点个赞或使用打赏功能进行鼓励。你的打赏将是我持续更新的动力。
下一篇文章,再见!
人生就象弈棋, 一步失误, 全盘皆输,这是令人悲哀之事;而且人生还不如弈棋,不可能再来一局,也不能悔棋。—— 弗洛伊德