设计博客数据方案,既针对博客定义数据模型.这里,模型表示为一个python类,并定义为django.db.models.Model的子类.其中,每个属性视为一个数据库字段.Django针对定义于models.py文件中的每一个模型创建一个表.当创建一个模型时,Django提供了一个使用的API,从而可方便地查询数据库中的对象.
首先定义一个Post模型,并向博客应用程序的models.py文件中添加下列代码行:
from django.db import models from django.utils import timezone from django.contrib.auth.models import User class Post(models.Model): STATUS_CHOICES = ( ('draft','Draft'), ('published','Published'), ) title = models.CharField(max_length=250) slug = models.SlugField(max_length=250,unique_for_date='publish') author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts') body = models.TextField() publish = models.DateTimeField(default=timezone.now) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft') class Meta: ordering = ('-publish',) def __str__(self): return self.title
这表示为博客帖子的数据模型.下面查看针对该模型定义的相关字段,如下所示:
- title表示为帖子标题字段.该字段定义为Charfield,在SQL数据库中将转换为VARCHAR列.
- slug字段用于URL中.作为一种简短的标记,slug仅包含字母、数值、下划线以及连字符.根据slug字段,可针对博客帖子构建具有较好外观的、SEO友好的URL.之前曾向该字段中添加了unique_for_date参数,进而可采用发布日期和slug对帖子构建URL.Django不支持多个帖子在既定日期拥有相同的slug.
- author字段表示为一个外键,并定义了多对一的关系.具体来说,我们将通知Django,每个帖子由某位用户填写,但一个用户可编写多个帖子.对于该字段,Django通过相关模型的主键在数据库中生成了一个外键.此时,我们将借助Django验证系统中的User模型.当删除引用对象时,on_delete参数指定了所使用的操作行为--这并非是Django规范,而是一类SQL标准.当采用CASCADE并删除引用用户时,数据库还将删除其所关联的博客帖子.我们使用related_name属性指定反向关系的名称(从user_set到Post),这可以方便地访问相关对象.
- body表示为帖子的主体,且设置为文本字段,同时转换为SQL数据库中的TEXT列
- publish表示为帖子的发布日期.此处使用了Django的时区now方法作为默认值,并以时区格式返回当前日期.我们可将其视为python标准方法datetime.now的时区版本
- created表示帖子的创建时间.鉴于此采用了auto_now_add,当创建某个对象时,日期将被自动保存.
- updated表示帖子最后一次更新时间.鉴于此采用了auto_now,因而当保存某个对象时,日期将被自动保存
- status显示了帖子的状态.由于使用了choices参数,因而该字段值仅设置为既定选择方案中的某一个方案
模型内的Meta类包含了元数据.默认状态下,当查询元数据时,将通知Django对publish字段中的结果以降序排序.通过负号前缀,可指定降序排列.据此,最新发布的帖子将首先加以显示
__str__()方法为默认的人们可读的对象表达方式,Django将在多处对其加以使用,如站点管理.
1.3.1 激活应用程序
为了使Django跟踪应用程序,同时可针对其模型创建数据表,我们需要对其予以激活,对此,可编辑settings文件,并向INSTALLED_APPS设置中加入blog.apps.BlogConfig,如下所示:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog.apps.BlogConfig', # 这是注册的app,格式为app名字.apps(py文件).类名 ]
BlogConfig类定义了应用程序的配置内容.当前,Django了解到应用程序针对项目处于活动状态,并可加载其模型
1.3.2 设置并使用迁移方案
前述内容对博格帖子创建了数据模型,我们需要对此定义数据库表.Django配置了迁移系统,跟踪模型产生的变化内容,并将其传送至数据库中.相应地,migrate命令可针对INSTALLED_APPS列出的全部应用程序执行迁移操作并同步对应的数据库(其中包含了当前模型和现有的迁移内容)
首先需要针对Post模型创建初始迁移.在项目的根目录中,可运行下列命令:
python manage.py makemigrations blog
对应输出结果如下:
Migrations for 'blog': blogmigrations 001_initial.py - Create model Post
Django在blog应用程序的migrations目录内仅生成了0001.inital.py文件,我们可以打开改文件查看迁移结果.迁移指定了在数据库中执行的其他迁移和操作的依赖关系,以便与模型变化同步.
下面考察Django在数据库中执行的SQL代码,以创建模型表.sqlmigrate命令将使用到迁移名称并在不执行SQL的情况下返回其SQL.运行以下命令并检查第一次迁移的SQL输出结果:
python manage.py sqlmigrate blog 0001
对应的输出结果如下:
BEGIN; -- -- Create model Post -- CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id")); CREATE INDEX "blog_post_slug_b95473f2" ON "blog_post" ("slug"); CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id"); COMMIT;
实际结果输出取决所用的数据库,上述输出结果为SQLite所生产.不难发现,Django通过组合应用程序名称以及模型(blog_post)的小写名称生产表名.另外,还可以使用db_table属性在模型的Meta类中为模型指定一个定制的数据库名称.Django对每个模型自动生成主键,但也可在模型字段中指定primary_key=True以对此进行覆写.此处,默认的主键表示为id列,并由一个整数构成,同时实现自动递增.该列对应于自动添加至模型中的id字段.
接下来将数据库与新模型同步.运行一下命令来应用现有迁移:
python manage.py migrate
对应输出结果如下所示:
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0001_initial... OK
我们只是为INSTALLED_APPS中列出的应用程序使用了迁移,包括我们的blog应用程序.在应用迁移之后,数据库反应了模型的当前状态.
当编辑models.py文件,以添加、移除或修改现有模型的字段时,或者添加新的方法时,则需要利用makemigrations命令创建新的迁移.该迁移使得Django可跟踪模型的变化状态.随后,还需将其与migrate命令一起应用,以使数据库与模型保持一致.