数据库与数据模型
django框架的设计也采用了MVC模式,但是基于MVC模式却更注重模型(Model)、模板(Template)、视图(View)。通过编写数据模型(Model)来完成对所有数据有关的事物,包括数据库中数据的存取等操作。
数据库
Mysql、SQLserver 2008、sqlite3 等数据库都可以在 django 中使用,而默认情况下,django 使用的是轻量级的sqlite3,在项目配置文件中可以进行数据库配置
# fbckf/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
而作为一个小型个人博客,使用 sqlite3 这个数据库就已经绰绰有余了,所以不用去更改配置文件
博客数据
博客主要是发布文章,文章中包含很多信息,比如标题、作者、类别、评论等,而类别和评论又包括了各自的信息。将数据分为以下两部分,也就是,我们将在数据库中建立两张表,每一部分中的信息就是各自表中的字段。
1.文章
标题 | 作者 | 类别 | 内容 | 摘要 | 创建时间 | 喜欢人数 |
---|---|---|---|---|---|---|
《绝望》 | fbckf | 散文 | 绝望啊... | 绝望... | 2018-6-2 | 999+ |
《白云谣》 | 先秦诗人 | 诗词 | 白云在天... | 白云在天... | 2018-6-8 | 9999+ |
2.类别
名称 | 简介 |
---|---|
散文 | 散文是一种抒发作者真情实感、写作方式灵活的记叙类文学体裁。 |
诗词 | 诗词,是指以古体诗、近体诗和格律词为代表的中国古代传统诗歌。 |
之所以要将类别和评论从文章中分离出来形成另的表格,是因为这样可以避免数据库中数据的重复存储
数据库模型
之前所说过,需要在数据库中创建三张表,用来存储博客的各种数据,创建的表就如之前所示的表格一样。一般情况下对数据库的 SQL语句 不熟悉的话,在进行数据库操作时是比较头疼的,幸运的是,django 已经将 SQL语句 转换成相对应的 python 语言,只需要在 blog/models.py
中编写相对应的 python 代码就好了,其中类对应数据库中的表格,类中的属性则对应数据库中的字段
数据
编写数据模型代码
# blog/models.py
from django.db import models
# auth是django内置的一个应用
from django.contrib.auth.models import User
# 对应数据库中类别的表,类名 Category 就是表的名称
# 继承了models.Model
class Category(models.Model):
# 属性 name 是表中的名称字段, name 是简单的字符串所以使用CharField()类型
# max_length=20 表示该字段最长为20字符,unique=True 表示该字段具有的唯一性
name = models.CharField(max_length=20, unique=True)
# 属性instructions 对应简介字段,因为 instructions 是文本,所以使用TextField()类型
# default=“” 表示该字段默认内容为空
instructions = models.TextField(max_length=100, default="")
class Article(models.Model):
title = models.CharField(max_length=50, unique=True)
# 一个作者有多篇文章,但是一篇文章只有一个作者,这是一对多的关系,所以使用 ForeignKey()类型
# ForeignKey() 将 注册的用户 User 和文章关联起来
# on_delete=models.CASCADE 表示当删除该用户时,该用户关联的文章也会一并删除
# null=True 表示允许为空 比如从别的平台转发文章
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
category = models.ForeignKey(Category, null=True, on_delete=models.CASCADE)
body = models.TextField()
abstract = models.TextField(max_length=50, default="")
# create_time 是时间,所以使用 DateTimeField()类型
# auto_now=True 表示自动添加该字段的值
create_time = models.DateTimeField(auto_now=True)
# PositiveIntegerField() 只允许正整数和0,因为likes字段不为负数和小数,所以使用该类型
likes = models.PositiveIntegerField(default=0)
django 内置的应用 auth(django.contrib.auth),负责整个网站的用户注册、登陆等功能,而 User 是该应用中用户的模型,就像 Category 类一样,在这里导入后与文章关联。
在编写模型代码时,需要根据字段的类型选择对应的字段类型函数,常用的有字符串类型(CharField)、文本类型(TextField)、日期类型(DateField、DateTimeField)、邮箱(EmailField)、整数类型(IntegerField)等。
article 与 category、author是一对多的关联关系所以使用 ForeignKey()关联类型,多对多的关联关系是 MangToManyFiled()。
评论建立另外一个应用来完成。
数据库迁移
完成模型代码编写事情后还没有结束,那只是单纯的写好 python 代码,就像只是写策划书,还没有真正去执行,所以还需要告诉 django,根据编写在models.py
中的代码,去执行相应的 SQL语句。
$ python manage.py makemigrations
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Article
- Create model Category
- Add field category to article
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, 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 blog.0001_initial... OK
Applying sessions.0001_initial... OK
执行以上命令之后,在查看一下项目的变化
$ tree fbckf
fbckf
├── blog
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── 0001_initial.cpython-35.pyc
│ │ └── __init__.cpython-35.pyc
│ ├── models.py
│ ├── __pycache__
│ │ ├── admin.cpython-35.pyc
│ │ ├── __init__.cpython-35.pyc
│ │ └── models.cpython-35.pyc
│ ├── tests.py
│ └── views.py
├── db.sqlite3
├── fbckf
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── settings.cpython-35.pyc
│ │ └── urls.cpython-35.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
在项目主目录中生成了一个新的文件
db.sqlite3
这就是 django 根据模型创建的数据库文件,博客的数据也将存储在里面blog/migrations
中的生成了0001_initial.py
文件,其中存放着 django 对数据库的操作记录,可以使用命令python manage.py sqlmigrate <应用名称> 0001
查看。
$ python manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Article
--
CREATE TABLE "blog_article" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(50) NOT NULL UNIQUE, "body" text NOT NULL, "abstract" text NOT NULL, "create_time" datetime NOT NULL, "likes" integer unsigned NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
--
-- Create model Category
--
CREATE TABLE "blog_category" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(20) NOT NULL UNIQUE, "instructions" text NOT NULL);
--
-- Add field category to article
--
ALTER TABLE "blog_article" RENAME TO "blog_article__old";
CREATE TABLE "blog_article" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(50) NOT NULL UNIQUE, "body" text NOT NULL, "abstract" text NOT NULL, "create_time" datetime NOT NULL, "likes" integer unsigned NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED, "category_id" integer NOT NULL REFERENCES "blog_category" ("id") DEFERRABLE INITIALLY DEFERRED);
INSERT INTO "blog_article" ("author_id", "body", "id", "create_time", "likes", "abstract", "category_id", "title") SELECT "author_id", "body", "id", "create_time", "likes", "abstract", NULL, "title" FROM "blog_article__old";
DROP TABLE "blog_article__old";
CREATE INDEX "blog_article_author_id_905add38" ON "blog_article" ("author_id");
CREATE INDEX "blog_article_category_id_7e38f15e" ON "blog_article" ("category_id");
COMMIT;
可以在输出中看到详细的 SQL语句
数据库操作
django提供了一个 shell,可以通过它来进行数据库的简单操作
$ python manage.py shell
Python 3.5.2 (default, Sep 14 2017, 22:51:06)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from blog.models import Category, Article
>>> c = Category(name="古诗", instructions="古诗,是中国古代诗歌的一种体裁,又称古体诗或古风,指的是产生于唐代以前并和唐代新出现的近体诗(又名今体诗)相对的一种诗歌体裁")
>>> c.save()
>>> c
>>> c.name
'古诗'
>>> c.instructions
'古诗,是中国古代诗歌的一种体裁,又称古体诗或古风,指的是产生于唐代以前并和唐代新出现的近体诗(又名今体诗)相对的一种诗歌体裁'
>>>
从
blog
应用的models.py
中导入Category
类,之后通过实例化一个对象,并调用save()
方法保存,这样就已经在数据库中插入了一条数据save()
方法继承自models.Model
实例化后 django 返回的是
这样不利于观察代码的执行情况,在每一个models.py
的类中写一个__str__
用以返回对象的name
属性
class Category(models.Model):
...
def __str__(self):
return self.name
$ python manage.py shell
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from blog.models import Category
>>> Category.objects.all()
]>
>>> c = Category.objects.get(name='古诗')
>>> c
>>>
因为文章类需要关联一个User
对象,所以这里直接使用命令创建一个超级用户,也方便接下来的管理
$ python manage.py createsuperuser
Username (leave blank to use 'csx'): fbckf
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.
leave blank to use 'csx'
是 django 检测到当前操作系统用户名称为 'csx' ,提示默认使用 'csx' 作为超级用户名称之后邮箱和密码,密码的强度比较严格,所以要好好记住自己设置的密码
$ python manage.py shell
>>> from django.utils import timezone
>>> from django.contrib.auth.models import User
>>> from blog.models import Category, Article
>>> auth = User.objects.get(username='fbckf')
>>> c = Category.objects.get(name='古诗')
>>> article = Article(title='白云谣', author=auth, category=c, body='白云在天,丘陵自出。道里悠远, 山川间之。将子无死,尚复能来。', abstract='白云在天,丘陵自出。', create_time=timezone.now(), likes=0)
>>> article.save()
>>> article.title
'白云谣'
>>> article.author
>>> article.body
'白云在天,丘陵自出。道里悠远,山川间之。将子无死,尚复能来。'
>>>
调用 django 内置模块
timezone
的now()
方法指定时间使用
get()
方法,指定取出用户 'fbckf' 和类别 '古诗'实例化一个 article 对象并保存
delete()
方法用于删除数据
总结
简单来说,整一个博客应用的编写就是围绕着对数据的操作进行的,数据的重要性不言而喻。也因此,数据库的操作也显的尤为重要,而 django 将SQL语句都封装起来,就使得可以通过编写 python 代码来进行数据库操作,这就意味着即使不懂 SQL语句 也可以使用数据库,极大的降低了 django 的使用门槛(当然 SQL语句 也是很重的)