django 入门笔记:数据模型

django 及 rest_framework 笔记链接如下:
django 入门笔记:环境及项目搭建
django 入门笔记:数据模型
django 入门笔记:视图及模版
django 入门笔记:Admin 管理系统及表单
django 入门笔记:通用视图类重构视图
django_rest_framework 入门笔记:Serializer
django_rest_framework 入门笔记:视图函数重构
django_rest_framework 入门笔记:分页,多条件筛选及权限认证设置
django 自带 user 字段扩展及头像上传

上一部分我们介绍了环境和项目的搭建,以及数据库的配置,那这一部分我们介绍和数据库相关方面的知识 -- 模型

创建 django 模型

我们需要在 "blog" 应用下的 models.py 文件中添加 django 数据库模型,模型类需要继承 models.Model 类,例如

from django.db import models
class Category(models.Model):
    # 可以通过第一个参数传入字符串设置别名
    name = models.CharField("分类", max_length=100)

    # 查找 Category 时,返回为一个 object 如果不重写 __str__ 方法返回数据直接显示 Category Object,
    # 重写该方法后,查找返回结果为该方法返回的值
    def __str__(self):
        return '<Category>[{}]'.format(self.name)
        
    # 通过 Meta 来修改数据表的信息
    class Meta:
        db_table = "category" # 修改数据库表名,默认表名会是 项目名_模型名 blog_category
        ordering =  ['-id'] # 修改排序方式,"-" 表示逆序

Model 的常用字段类型还是比较多的,下面将介绍常用的字段类型和关系类型,以及字段类型的限制参数。

Model 的常用字段类型
  1. models.AutoField 自增列 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True
  2. models.CharField  字符串  指定 max_length 参数设置最大长度
  3. models.BooleanField  布尔类型
  4. models.DateField  日期类型 对于参数,auto_now = True 则每次更新都会更新这个时间,auto_now_add 则只是第一次创建添加,之后的更新不再改变
  5. models.DateTimeField  日期类型 同 models.DateField
  6. models.EmailField  字符串类型(正则表达式邮箱)
  7. models.FloatField  浮点类型
  8. models.IntegerField  整型
  9. models.BigIntegerField  长整型
  10. models.IPAddressField  字符串类型(ip4正则表达式)
  11. models.GenericIPAddressField  字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6
  12. models.TextField  字符串类型 同 CharField, 可以设置更长的字符串
  13. models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
  14. models.URLField  字符串,地址正则表达式
  15. models.ImageField 图片类型
  16. models.FilePathField 文件类型
Model 的连表结构
  1. 一对多:models.ForeignKey(其他表) 例如 ModelA 中有个字段指向 ModelB

    # 最好加上 on_delete 属性, 否则可能会报错
    b = models.ForeignKey(ModelB,on_delete=models.CASCAED)
    

    ModelA 为”多“,ModelB 为”一“

  2. 多对多:models.ManyToManyField(其他表) 例如 ModelA 中有个字段指向 ModelB

    bs = models.ManyToManyField(ModelB)
    

    ModelA 可以对应多个 ModelB 的值,同样 ModelB 可以对应多个 ModelA 的值

  3. 一对一:models.OneToOneField(其他表) 例如 ModelA 中有字段指向 ModelB

    b = models.OneToOneField(ModelB)
    

    ModelA 只能对应 ModelB 中特定的值,同样 ModelB 也只能对应 ModelA 中特定的值

Model 的常用设置参数
  1. null=(True/False) 数据库中字段是否可以为空
  2. blank=(True/False) django的 Admin 中添加数据时是否可允许空值
  3. primary_key=(True/False) 主键,对 AutoField 设置主键后,就会代替原来的自增 id 列
  4. auto_now=(True/False) 自动创建---无论添加或修改,都是当前操作的时间,在 MySql 下存在过滤月份时候数据为空,解决方案参考 MySql 文档 Section 10.6
  5. auto_now_add=(True/False) 自动创建---永远是创建时的时间
  6. choices=(xx,xx,xx) 可选择列表项,通常是一个列表或者元组
  7. max_length=(int) 最大长度,多和字符串类型配合使用
  8. verbose_name='xxxx' Admin 中字段的显示名称
  9. name|db_column 数据库中的字段名称
  10. unique=(True/False) 是否可以重复
  11. db_index=(True/False) 是否设置为索引
  12. editable=(True/False) 在Admin里是否可编辑
  13. error_messages='xxxx' 错误提示
  14. auto_created=(True/False) 是否自动创建
  15. help_text='xxxx' 在 Admin 中提示帮助信息
  16. upload-to='xxxx' 上传到哪个位置,与 ImageField,FfileField 配合使用

创建完模型后,我们需要根据模型来创建数据库,设计到数据库迁移的知识

数据库的迁移

我们通过命令行切换到 manage.py 文件夹,分别运行如下命令行

  1. python manage.py makemigrations 运行后会在相应应用下的 migrations 目录生成一个 0001_initial.py(0001会根据迁移的次数进行递增),用于记录对模型的修改
  2. python manage.py migrate 运行后将 model 中的操作转换成为数据库语言,作用于数据库,对数据库进行相应的修改
    如果对命令行做了什么动作,我们可以通过运行如下命令行查看具体的数据库操作python manage.py sqlmigrate blog 0001 其中 blog 0001 根据实际项目进行替换
数据库插入数据

创建好数据库进行数据添加,可以通过如下操作进行

from blog.models import Category, Tag
c = Category('test category')
c.save()
t = Tag('test tag')
t.save()

打开数据库可以看到插入的数据

数据库查找数据

插入数据后,查找数据库内的数据可以通过如下操作进行

# 查找某个表所有的数据,返回<QuerySet[...]>
from blog.models import Category
c_list = Category.objects.all()
# 查找某个特定的数据,如果数据不存在会抛出错误 blog.models.DoesNotExist,
# 存在则返回 Object,如果重写了 __str__ 方法,则返回该方法所指定的值
c_test = Category.objects.get(name='test category')
# 也可以通过 filter 关键词进行查找
c_test = Category.objects.filter(name='test category, id__lt=10)
c_test = Category.objects.filter(id__range=[0, 10])
# 还可以使用 startswith,istartswith, endswith, iendswith 等条件
# .values() 和 .values_list() 区别
# .values() 取出某一列,每个元素是一个字典,.values_list() 取出的元素是一个个元组
# 如下语句得到的结果为 <QuerySet [{'name': 'test category', 'id': 1}]>
print(Category.objects.filter(name='test category').values('name', 'id')) 
# 如下语句得到的结果为 <QuerySet [('test category', 1)]>
print(Category.objects.filter(name='test category').values_list('name', 'id'))
# exclude 查询条件外的数据
Category.objects.exclude(id__gt=2)   即查找 id 不大于 2 的数据
# 通过 order_by 进行排序
Category.objects.all().order_by('-id') # 逆序排序,逆序排序只需要在排序字段前加"-"号即可
# 删选某个范围内的数据 类似于 SQL 语句中的 OFFSET 10 LIMIT 10
Category.objects.all()[10: 20] # 获取列表中 10-20 的数据
# aggregate 操作符(出了求和 Count 还有 Avg, Max, Min 等,通过 django.db.models 导入)
print(Category.objects.aggregate(Count('name')))    # {'name__count': 5}
# 也可以指定结合后的字段名
print(Category.objects.aggregate(category_count=Count('name)))  # {'category_count': 5}
# annotate 操作符
# 假设 Post 表中有个字段指向 Category
# category = models.ForeignKey(Category) 在表 Category 中需要统计某个 category 下 post 数量,
# 但是表 Category 中没有 post_count 字段,那么可以通过 annotate 操作符来进行统计
c_list = Category.objects.annotate(post_count=Count('post'))
print(c_list[0].post_count) # 12
# "__" 的操作
# 大于,小于操作
Categroy.objects.fileter(id__gt=1, id__lt=10) # 查找 id 介于 1 和 10 之间的数据
# in
Category.objects.filter(id__in=[11, 22, 33]) # 查找 id 为 11,22,33 的值
Category.objects.exclude(id__in=[11, 22, 33]) # not in
# contains
Category.objects.filter(name__contains="test") 查找 name 字段包含 test 的值
Category.objects.filter(name__icontains="test") # 大小写不敏感
# range
Caregory.objects.filter(id__range=[1, 10]) # 查找 id 介于 1 和 10 之间的数据,即 between and
# 类似的包括 startwith, istartwith, endwith, iendwith 等
数据库修改数据

对存在的数据进行修改,可通过如下操作进行

c = Category.objects.get(name='test category')
c.name = 'new test category'
c.save()
删除数据库数据

对存在数据库中的数据进行删除,可以通过如下操作进行

# 删除某条特定的数据
c = Category.objects.get(name='new test category')
c.delete()
# 删除全部的数据
c_list = Category.objects.get()
for c in c_list:
    c.delete()

更多的数据库操作 API 查看官方的 API django 数据库操作 API

使用原生 SQL 语句操作数据库

django 支持使用原生语句操作数据库

from django.db import connection
cursor = connection.cursor()
# 原生 SQL 语句放在 execute 中使用
cursor.execute("SELECT c.id, c.name FROM blog_category as c")
# 获取查询到的第一个数据
row = cursor.fetchone()
# 获取全部查询到的数据
rows = cursor.fetchall()

最后附上整个项目的地址:blog_project

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

推荐阅读更多精彩内容