django2.0入门教程第二节

继上篇 django2.0入门教程第一节,生成了投票应用,接下来讲解如何使用django的模型与数据库进行交互

数据库设置

打开mysite/settings.py,可看到默认情况下,django使用的是sqlite3数据库

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

本教程便以默认的sqlite3作为数据库

注意settings.py的INSTALLED_APPS选项,默认情况下,设置如下:

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

这个选项代表django激活的应用,这些应用能被多个项目使用,你也可以将这些应用进行打包分发

有些应用要求我们必须至少要有一个数据库,如,django的后台,因此,让我们先来执行以下命令:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

以上命令将django激活的应用所需的数据表创建好了

创建模型

django的模型(models)在本质上就是对数据表的定义。在django中是不需要直接与数据库交互的,所有对数据库的操作都可以映射为模型类的操作,有一个数据表,就有一个模型类与之对应

polls/models.py

#_*_coding:utf8_*_

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)

以上代码相当简单明了,每个类都是models.Model的子类,类中的每个属性映射为一个字段,并标识了这些字段的类型

激活模型

mysite/settings.py

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    # ...
]

生成迁移

$ python manage.py makemigrations polls
Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Choice
    - Create model Question
    - Add field question to choice

自动生成了polls/migrations/0001_initial.py文件,现在还没有真正创建数据表,需要再执行数据迁移才能生成数据表,在此之前,先来预览要执行的sql语句:

$ python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
INSERT INTO "polls_choice" ("id", "choice_text", "votes", "question_id") SELECT "id", "choice_text", "votes", NULL FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;

以上的sql语句就是从polls/migrations/0001_initial.py文件中生成

执行迁移,即执行以上的sql语句:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying polls.0001_initial... OK

至此,models类的代码就转换成了数据表

django命令行交互

django提供了一个交互的shell,执行python manage.py shell即可进入交互界面,默认的交互界面不太好用,建议安装ipython, pip install ipython, 这样,django会自动进入ipython的交互界面,就拥有了华丽的语法高亮以及智能流畅的代码自动补全功能

用交互客户端测试对数据库的操作:

$ python manage.py shell
Python 3.6.2 (default, Nov 22 2017, 14:09:09)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

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

In [2]: from django.utils import timezone

In [3]: q = Question(question_text='问题1', pub_date=timezone.now())
In [4]: q.save() # 添加一条记录

In [5]: q.id
Out[5]: 1

In [6]: q.question_text
Out[6]: '问题1'

In [7]: q.pub_date
Out[7]: datetime.datetime(2017, 12, 29, 8, 39, 20, 968497, tzinfo=<UTC>)

In [8]: q.question_text = '问题2'

In [9]: q.save()

In [10]: Question.objects.all()
Out[10]: <QuerySet [<Question: Question object (1)>]>

以上对数据库的查询,得到的只是一个对象,看起来并不直观,我们修改下polls/models.py,让结果显示更友好

修改返回的数据格式: polls/models.py

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__()函数将会返回我们定义好的数据格式。此外,我们还可以在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)

注意,修改models文件后,需要退出再重新进入交互界面,退出按ctrl+d

$ python manage.py shell
Python 3.6.2 (default, Nov 22 2017, 14:09:09)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

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

In [2]: Question.objects.all() # 获取所有问题
Out[2]: <QuerySet [<Question: 问题2>]>

In [3]: Question.objects.filter(id=1) # 获取id为1的数据
Out[3]: <QuerySet [<Question: 问题2>]>

In [8]: Question.objects.filter(question_text__startswith='问题') # 获取内容包含'问题'的数据
Out[8]: <QuerySet [<Question: 问题2>]>

In [9]: from django.utils import timezone

In [10]: current_year = timezone.now().year

In [11]: Question.objects.get(pub_date__year=current_year)
Out[11]: <Question: 问题2>

In [12]: Question.objects.get(id=2) # 当获取的数据不存在时,会报以下错误
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
<ipython-input-12-75091ca84516> in <module>()
----> 1 Question.objects.get(id=2)


In [13]: Question.objects.get(pk=1)
Out[13]: <Question: 问题2>

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

In [15]: q.was_published_recently() # 调用自定义的方法
Out[15]: True

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

In [17]: q.choice_set.all()
Out[17]: <QuerySet []>
In [19]: q.choice_set.create(choice_text='选项1', votes=0)
Out[19]: <Choice: 选项1>

In [20]: q.choice_set.create(choice_text='选项2', votes=0)
Out[20]: <Choice: 选项2>

In [21]: c = q.choice_set.create(choice_text='选项3', votes=0)

In [22]: c.question
Out[22]: <Question: 问题2>

In [23]: q.choice_set.all()
Out[23]: <QuerySet [<Choice: 选项1>, <Choice: 选项2>, <Choice: 选项3>]>

In [24]: q.choice_set.count()
Out[24]: 3
In [25]: Choice.objects.filter(question__pub_date__year=current_year)
Out[25]: <QuerySet [<Choice: 选项1>, <Choice: 选项2>, <Choice: 选项3>]>

In [26]: c = q.choice_set.filter(choice_text__startswith='选项3')

In [27]: c.delete()
Out[27]: <bound method QuerySet.delete of <QuerySet [<Choice: 选项3>]>>

In [29]: Choice.objects.filter(question__pub_date__year=current_year)
Out[29]: <QuerySet [<Choice: 选项1>, <Choice: 选项2>]>

创建后台管理员

django自带了一个管理后台,我们只需创建一个管理员用户即可使用

创建一个后台管理员用户:

$ python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

密码自己设置,如设置为: 123admin456

访问:http://127.0.0.1:8000/admin

输入账号密码进入后台

admin.png

后台并没有看到我们建立的Question模型,需要将模型引入,才能在后台进行维护:

polls/admin.py

#_*_coding:utf8_*_
from django.contrib import admin
from .models import Question
admin.site.register(Question)

刷新后台页面,此时就能看到Question模型已经展现在页面了:

question.png

接下来就可以对数据进行添加,修改和删除操作

edit.png

源码下载

源码包地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容