Django之深入了解ORM
Django ORM操作
常用字段
models中所有的字段类型其实本质就那几种,整形varchar什么的,都没有实际的约束作用,虽然在models中没有任何限制作用,但是还是要分门别类,对于校验性组件校验非常有用
就比如说邮箱类型,你在输入邮箱的时候如果不按照邮箱格式输入,瞎鸡儿输入会提示你不合法,虽然输入的是字符串,但是不是规定的邮箱字符串
字段 | 描述 |
---|---|
AutoField | int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。 |
IntegerField | 一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,) |
BigIntegerField | |
CharField | 字符类型对应MySQL的varchar类型,必须提供max_length参数, max_length表示字符长度。 |
DateField | 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。 |
DecimalField | 10进制小数, max_digits,小数总长度 ,decimal_places,小数位长度 |
EmailField | email字段,内部还是varchar(254) |
BooleanField | 布尔值,传True或False,自动转成1/0 |
TextField | 存储大段文本 |
FileField | 专门用来存放文件路径,传值的时候,直接传文件对象,将路径保存到数据库 |
关系字段 | 描述 |
ForeignKey | 关系字段,外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。 |
OneToOneField | 一对一字段。 |
ManyToManyField | 多对多表关系并且这一张多对多的关系表是有Django自动帮你建 |
常用字段参数
参数 | 描述 |
---|---|
null | 用于表示某个字段可以为空。 |
unique | 如果设置为unique=True 则该字段在此表中必须是唯一的 。 |
db_index | 如果db_index=True 则代表着为此字段设置索引。 |
default | 为该字段设置默认值。 |
DateField和DateTimeField | 描述 |
auto_now_add | 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。 |
auto_now | 配置上auto_now=True,每次更新数据记录的时候会更新该字段。 |
关系字段参数 | 描述 |
to | 设置要关联的表 |
to_field | 设置要关联的表的字段 |
on_delete | 当删除关联表中的数据时,当前表与其关联的行的行为。 |
db_constraint | 是否在数据库中创建外键约束,默认为True。 |
自定义字段
Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,
但是Django允许我们自定义新的字段,下面我来自定义对应于数据库的char类型
自定义字段在实际项目应用中可能会经常用到
from django.db import models
# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
字段合集和对应关系
我们来创建一张表:
models.py:
class Books(models.Model):
title = models.CharField(max_length=254)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField()
将表同步到MySQL中:
python3 manage.py makemigrations
python3 manage.py migrate
然后我们在django测试文件中,如果单纯的测试某个py文件,需要手动配置测试脚本
app01/tests.py:
# Create your tests here.
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
from app01 import models
# 下面开始写测试的代码。
# 创建数据------------------------------------------------------------------------
# 1. create 方法
models.Books.objects.create(title='三国演义',price=123,publish_date='2019-11-11')
from datetime import date
ctime = date.today()
models.Books.objects.create(title='红楼梦',price=888,publish_date=ctime)
# 2. 利用对象的绑定方法创建数据
book_obj = models.Books(title='西游记',price=666,publish_date='2000-11-11')
book_obj.save()
# 插入的数据
# id title price publish_date
# 4 三国演义 123 2019-11-11
# 5 红楼梦 888 2019-11-27
# 6 西游记 666 2000-11-11
# 修改数据------------------------------------------------------------------------
'''
利用filter 自动查询当前表的主键字段,pk代表primary_key
filter查询出来的是一个queryset对象:
只要是queryset的对象就可以无限制的调用queryset的方法
只要是queryset的对象就可以点query查看当前结果内部对应的sql语句
'''
# 1. 利用queryset方法修改数据
models.Books.objects.filter(pk=4).update(price=444)
# 2. 利用对象方法修改数据
book_obj = models.Books.objects.get(pk=1)
book_obj.price = 222
book_obj.save() # 不推荐使用,推荐使用queryset方法
'''
利用对象修改,内部其实是将所有的字段重新写进去
get 和 filter的区别:
filter 获取到的是一个queryset对象,类似于一个列表,没有数据的时候不会报错
get获取到的数据就是数据本身,但是没有数据的时候会报错
'''
# 删除数据------------------------------------------------------------------------
# 1. 利用queryset方法 :delete()
models.Books.objects.filter(pk=4).delete()
# 2. 对象的方法
book_obj = models.Books.objects.get(pk=4)
book_obj.delete()
# 如果你想直接查看所有的orm语句内部对应的sql语句,可以在配置文件中配置:
settings.py:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
单表操作
方法(加括号使用) | 描述 |
---|---|
all | 查询所有,返回QuerySet对象 |
filter | 筛选,相当于原生SQL的where条件,返回QuerySet对象 |
get | 筛选,获取数据对象本身,如果不存在报错,并且查询条件必须是唯一的。 |
first | 取QuerySet对象中第一个数据对象 |
last | 取QuerySet对象中最后一个数据对象 |
count | 统计数据的条数 |
values | 获取数据对象中指定的字段的值,返回列表套字典的QuerySet对象 |
values_list | 获取数据对象中指定的字段的值,返回列表套元组的QuerySet对象 |
order_by | 指定字段进行排序,默认升序,在字段前加- 是降序 |
reverse | 颠倒顺序,前提是颠倒的对象必须有顺序,也就是order_by过后的 |
exclude | 查询排除什么之外,返回QuerySet对象 |
exists | 判断查询结果是否有值,返回布尔值 |
distinct | 对指定字段查询出来的结果进行去重操作 |
# 查询数据 13 条------------------------------------------------------------------------
# 1. all() 查询所有,返回queryset对象
print(models.Books.objects.all())
# 2. filter() 筛选 相当于原生sql语句里面的where关键字,返回queryset对象
print(models.Books.objects.filter(pk=4))
# 3. get() 筛选 获取的数据是对象本身,数据不存在直接报错,并且查询条件必须唯一,返回数据对象本身
print(models.Books.objects.get(pk=4))
# 4. first() 获取queryset对象中第一个数据对象 返回数据对象
print(models.Books.objects.filter(pk=4).first())
# 5. last() 获取queryset对象中最后一个数据对象 返回数据对象
print(models.Books.objects.filter(pk=4).last())
# 6. count() 统计数据的条数 返回数字
print(models.Books.objects.count())
# 7. values() 获取数据对象中指定的字段的值,可以指定多个,返回queryset对象,列表套字典
print(models.Books.objects.values('title','price'))
# 8. values_list() 获取数据对象中指定的字段的值,可以指定多个,返回queryset对象,列表套元组
print(models.Books.objects.values_list('title','price'))
# 9. order_by() 按照指定的字段排序,默认是升序,在字段前面加 - 是降序
print(models.Books.objects.order_by('pk').values('pk'))
print(models.Books.objects.order_by('-pk').values('pk'))
# 10. reverse() 颠倒顺序,前提是颠倒的对象必须有顺序,排序之后的
print(models.Books.objects.order_by('pk').reverse().values('pk'))
# 11. exclude() 查询条件排除什么
print(models.Books.objects.exclude(pk=4).values('pk'))
# 12. exists() 判断查询结果是否有值,返回的是布尔值
print(models.Books.objects.exists())
# 13. distinct() 对查询结果去重,前提是数据完全相同的情况下
print(models.Books.objects.values('title','price').distinct())
双下划线查询
方法 | 描述 |
---|---|
__gt | 字段大于什么什么值 |
__lt | 字段小于什么什么值 |
__gte | 字段大于等于什么值 |
__lte | 字段小于等于什么值 |
__in | 字段是什么或什么的值,or的关系 |
__range | 字段是什么和什么之间的值,btwen..and... |
__year | 字段的年份是什么什么的值 |
__month | 字段的月份是什么什么的值 |
# 下划线查询------------------------------------------------------------------------
# 1. 查询价格大于500的书
print(models.Books.objects.filter(price__gt=500).values('title'))
# 2. 查询价格小于500的书籍
print(models.Books.objects.filter(price__lt=500).values('title'))
# 3. 查询价格大于等于500的书籍
print(models.Books.objects.filter(price__gte=500).values('title'))
# 4. 查询价格小于等于500的书籍
print(models.Books.objects.filter(price__lte=500).values('title'))
# 5. 查询价格是222 或 444 或 500 的书籍
print(models.Books.objects.filter(price__in=[222,444,500]).values('title'))
# 6. 查询价格在200到800之间的书籍 顾头也顾尾
print(models.Books.objects.filter(price__range=(200,800)).values('title'))
# 7. 查询出版日期是2019年的书籍
print(models.Books.objects.filter(publish_date__year='2019').values('title'))
# 8. 查询出版日期是11月份的书籍
print(models.Books.objects.filter(publish_date__month='11').values('title'))
模糊查询
MySQL中的模糊查询,关键字like,模糊匹配的符号:%
、_
方法 | 描述 |
---|---|
__startswith | 字段的值以什么什么开头的值 |
__endswith | 字段的值以什么什么结尾的值 |
__contanins | 字段的值包含什么什么的值,区分大小写 |
__icontanins | 字段的值包含什么什么的值,不区分大小写 |
# 模糊查询------------------------------------------------------------------------
# 1. 查询书籍是以三开头的书
print(models.Books.objects.filter(title__startswith='三').values('title'))
# 2. 查询书籍是以三结尾的书
print(models.Books.objects.filter(title__endswith='三').values('title'))
# 3. 查询书籍名称中包含游字的书籍
print(models.Books.objects.filter(title__contains='游').values('title'))
# 4. 查询书籍名称中包含字母p的书籍,区分大小写
print(models.Books.objects.filter(title__contains='p').values('title'))
# 5. 查询书籍名称中包含字母p的书籍,区分大小写
print(models.Books.objects.filter(title__icontains='p').values('title'))
多表操作
一对多字段数据的操作
为了方便操作,我们创建图书管理系统相关表来演示多表操作
models.py:
class Book(models.Model):
title = models.CharField(max_length=254)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
'''
auto_now :每次修改数据的时候,会自动更新时间
auto_now_add :当数据创建出来的时候,自动将创建时间记录下来
'''
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=254)
addr = models.CharField(max_length=254)
class Author(models.Model):
name = models.CharField(max_length=254)
email = models.EmailField(max_length=254)
author_detail = models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
add = models.CharField(max_length=254)
# 一对多字段数据的增删改查------------------------------------------------------------------------
# 一对一字段的数据的修改和一对多一样的。
# 增
# 第一种方式:
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(title='红楼梦',price=444,publish=publish_obj)
# 第二种方式:
models.Book.objects.create(title='三国演义',price=222,publish_id=1)
# 改
# 第一种方式:
models.Book.objects.filter(pk=2).update(publish_id=2)
# 第二种方式:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=2).update(publish=publish_obj)
# 删 默认就是级联删除,级联更新
models.Publish.objects.filter(pk=1).delete()
多对多字段数据的操作
方法 | 描述 |
---|---|
add | 能够在第三张表中添加数据既支持传数字,也支持传对象,可以传多个值 |
set | 修改第三张表中的数据,需要传一个可迭代对象进去例如元组,列表,容器类元素可以是数字或者对象 |
remove | 删除第三张表中的数据,既支持传数字,也支持传对象,可以传多个值 |
clear | 清空 删除书籍相关的记录,下线,括号内不需要传递参数 |
# 多对多字段数据的增删改查------------------------------------------------------------------------
# 增
book_obj = models.Book.objects.filter(pk=2).first()
# print(book_obj.authors)
# app01.Author.None 表示着已经跨到第三张表了
# 给当前这一本书绑定作者,可以写多个
book_obj.authors.add(1)
book_obj.authors.add(1,2)
# 也可以增加对象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj1,author_obj2)
'''
add 方法:
能够在第三张表中添加数据
既支持传数字,也支持传对象,可以传多个值
'''
# 改
# 修改id为2的书籍的作者
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set((1,))
book_obj.authors.set((1,2))
# 也可以修改为对象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj1,author_obj2))
'''
set 方法:
修改第三张表中的数据,
需要传一个可迭代对象进去例如元组,列表,
容器类元素可以是数字或者对象
'''
# 删
# 删除id为2的书籍的作者
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.author.remove(1,2)
# 也可以传对象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.author.remove(author_obj1, author_obj2)
'''
remove 方法:
删除第三张表中的数据,既支持传数字,也支持传对象,可以传多个值
'''
# 清空:
# 删除id为2 的书籍(包括作者信息也删除)
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.clear()
'''
clear 方法:
清空 删除书籍相关的记录,下线,括号内不需要传递参数
'''
跨表查询
在使用跨表查询的时候,要注意一点,
要明白关系字段在哪一方?
从有关系字段的那一方查的话就是正向查询,查询按关系字段查询查。
从没有关系字段的那一方查的话就是反向查询,查询按小写的表名查。
基于对象的跨表查询
方法 | 描述 |
---|---|
all() | 当正向查询点击外键字段数据有多个的情况下也就是多对多查询,需要加.all() |
_set | 反向查询的时候 表名小写并且加_set |
子查询
# 跨表查询------------------------------------------------------------------------
# 基于对象的跨表查询
# 1. 查询书籍主键为2的出版社名称
# 正向查询,先查书籍对象,一对多查询
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish.name)
# 2. 查询书籍主键为2的作者姓名
# 正向查询,先查书籍对象,多对多查询
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors) # app01.Author.None
print(book_obj.authors.all().values('name'))
# 3. 查询作者是qinyj的手机号码
# 正向查询,先查作者对象,一对一查询
author_obj = models.Author.objects.filter(name='qinyj').first()
print(author_obj.author_detail.phone)
'''
什么时候需要加 all:
当正向查询点击外键字段数据有多个的情况下
也就是多对多查询,需要加.all()
'''
# 4. 查询出版社是东方出版社出版过的书籍
# 反向查询,先查出版社对象,一对多查询
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set.all().values('title'))
# 5. 查询作者是qinyj写过的书籍
# 反向查询,先查作者对象,多对多查询
author_obj = models.Author.objects.filter(name='qinyj').first()
print(author_obj.book_set.all().values('title'))
# 6. 查询手机号是111111的作者姓名
# 反向查询,先查作者详情表的对象,一对一查询
author_detail_obj = models.AuthorDetail.objects.filter(phone='111111').first()
print(author_detail_obj.author.name)
'''
什么时候反向查询的时候表名小写并且加_set
一对多
多对多
一对一不需要加
'''
基于双下划线的跨表查询
联表查询
双下划线,链式操作:__
# 基于双下划线的跨表查询 联表操作------------------------------------------------------------------------
# 1. 查询书籍id为2的出版社名称
# 正向查询:
# values中写外键名就相当于跨到外键字段所在的表中了
print(models.Book.objects.filter(pk=2).values('publish__name'))
# 反向查询:
print(models.Publish.objects.filter(book__pk=2).values('name'))
# 2. 查询书籍id为2的作者的姓名
# 正向查询:
print(models.Book.objects.filter(pk=2).values('authors__name'))
# 反向查询:
print(models.Author.objects.filter(book__pk=2).values('name'))
# 3. 查询作者是qinyj的地址
# 正向查询:
print(models.Author.objects.filter(name='qinyj').values('author_detail__add'))
# 反向查询:
print(models.AuthorDetail.objects.filter(author__name='qinyj').values('add'))
# 4. 查询出版社是东方出版社出版过的书的名字
# 正向查询:
print(models.Book.objects.filter(publish__name='东方出版社').values('title'))
# 反向查询:
print(models.Publish.objects.filter(name='东方出版社').values('book__title'))
# 5. 查询书籍id是2的作者的手机号
# 正向查询:
print(models.Book.objects.filter(pk=2).values('authors__author_detail__phone'))
# 反向查询:
print(models.Author.objects.filter(book__pk=2).values('author_detail__phone'))
聚合函数
aggregate
聚合函数 | 描述 |
---|---|
Max | 最大值 |
Min | 最小值 |
Sum | 求和 |
Count | 计数 |
Avg | 平均数 |
'''
聚合函数
'''
from django.db.models import Max,Min,Count,Avg,Sum
# 筛选出价格最高的书籍
print(models.Book.objects.aggregate(ct=Count('price'))) # {'ct': 2}
# 筛选出价格最低的书籍
print(models.Book.objects.aggregate(mn=Min('price'))) # {'mn': Decimal('222.00')}
# 求书籍价格总和
print(models.Book.objects.aggregate(sm=Sum('price'))) # {'sm': Decimal('666.00')}
# 求书籍价格平均值
print(models.Book.objects.aggregate(ag=Avg('price'))) # {'ag': 333.0}
# 联用
print(models.Book.objects.aggregate(Max('price')),Min('price'),Sum('price'),Count('price'))
分组查询
annotate
'''
分组查询,通常和聚合函数一起使用
'''
# 1. 统计每一本书的 书名和对应的作者个数
print(models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num'))
# 2. 统计每各出版社卖的最便宜的书的价格
print(models.Publish.objects.annotate(book_num=Min('book__price')).values('name','book_num'))
# 3. 按照指定的字段进行分组
print(models.Publish.objects.values('name').annotate(max_price=Max('book__price')).values('name','max_price'))
# 4. 统计不止一个作者的图书
# 首先拿到书对应的作者数,再筛选出大于一的图书,作者个数
print(models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num'))
# 5. 查询每个作者出的书的总价格
print(models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price'))
F与Q查询
'''
F 查询
'''
from django.db.models import F,Q
# 1. 查询库存数大于卖出数的书籍
print(models.Book.objects.filter(kucun_num__gt=F('maichu_num')).values('title'))
# 2. 将所有书的价格都上涨100块
models.Book.objects.all().update(price=F('price')+100)
# 3. 将所有书的名字后面都加上 后缀名
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'),Value('新款')))
'''
Q 查询
'''
# 1. 查询书籍名是三国演义或者 库存数是500的书籍
print(models.Book.objects.filter(title='三国演义',kucun_num=500)) # 默认是and的关系
print(models.Book.objects.filter(Q(title='三国演义') | Q(kucun_num=500))) # 用了 | 就是or的关系
print(models.Book.objects.filter(~Q(title='三国演义') | Q(kucun_num=500))) # 用了 | 就是or的关系
'''
Q对象高级用法
'''
q = Q()
q.connector = 'or' # 默认是and,可以改成or
q.children.append(('title','三国演义'))
q.children.append(('kucun_num',500))
print(models.Book.objects.filter(q))
ORM事务
还记得在Mysql数据库中的事务操作吗?
在MySQL中只有使用Innodb数据库引擎的数据库或表才支持使用事务
事务必须满足4个条件(ACID):
- 原子性:一个事务中的所有操作,要么全部执行,要么全部回滚,中间不会结束在任何一个环节。
- 一致性:在事务开始和事务结束之后,数据不会出错
- 隔离性:数据库允许多个并发事务同时对数据进行读写和修改,每个事务相互隔离
- 持久性:事务处理结束后,对数据的修改是永久的
from django.db import transaction
with transaction.atomic():
# 在缩进的代码中书写数据库的操作
# 该缩进下的所有代码,都是一个事务
pass
# 对整个view视图开启事务
@transaction.atomic
def index(request):
//ORM操作
return ....
例子
1.创建一个项目,新建一个APP(基础操作,这里不再赘述)
2.通过ORM创建生成表
from django.db import models
class UserInfo(models.Model):
username = models.CharField("用户",max_length=32)
balance = models.CharField("余额",max_length=32)
注意啊:踩过的坑,涉及金融计算,涉及小数啊,要求特别精确的,我们用字符串存储。
如果是金融计算的话,我们用一个decimal来进行计算。
3.我们给数据库加两条数据,用来模拟两个用户之间的转账
4.配置URL
5.创建对应的视图函数
from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F
def index(request):
try:
with transaction.atomic():
models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
except Exception as e:
return HttpResponse("出现错误<%s>"%str(e))
return HttpResponse("执行成功")
当我们访问index的时候,会进行一次转账操作
6.现在,我们让他报错
from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F
def index(request):
try:
with transaction.atomic():
models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
raise 一个错误
models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
except Exception as e:
return HttpResponse("出现错误<%s>"%str(e))
return HttpResponse("执行成功")
我们再次查看数据库文件,如果没有数据的原子性操作,我们第一条sql执行完报错,那钱肯定是减去了
但是,我们进行的是原子性的操作,你会发现钱没有减诶。
完美,没毛病
数据库中的三大范式
范式(Normal Form),缩写NF,规范化形式,简称范式。
目的是增加数据有效性,减少数据冗余,提高存储效率
- 1NF:数据库中的每一个字段,必须是不可拆分的最小单位。
- 2NF:表中所有字段都必须有意义,一个表只描述某一个事物
- 3NF:表中不能有其他表中存在的、存储相同信息的字段,通常是通过外键去建立关联,外键约束
第一范式(1NF)
数据库中的每一个字段,必须是不可拆分的最小单位。
即一个字段就表示一个意思,表中不能同时有2个字段来表示同一个意思
正例:
根据业务需求来合理使用行政区域
反例:
其中 address 可以再分为省、市、地区(县)、街道、详细地址,违反了第一范式。
第二范式(2NF)
表中所有字段都必须有意义,一个表只描述某一个事物
主键存在的意义就是唯一的标识表中的某一条记录,如果某一列和该行记录没关系,也就没必要存在。
反例:
此表中,天气(weather字段)和用户没啥关系,也就不存在依赖关系,所不符合 第二范式。正确的做法应)该删除此列,如有其他需要可单独存在一张表中。
第三范式(3NF)
表中不能有其他表中存在的、存储相同信息的字段,通常是通过外键去建立关联,外键约束
反例:
上面是一个订单表,字段从左至右以此是:订单id、买家id、买家名称、买家性别、买家年龄、订单状态。其中字段buyer_name、buyer_gender、buyer_age 是依赖于字段 buyer_info_id,违反 第二范式。
正例:
订单表
买家信息表
数据库五大约束
- 主键约束(Primary Key):非空唯一,例如 将UserId作为主键
- 唯一约束(Unique):唯一,可以空,但只能有一个,例如 身份证号唯一,因为每个人的都不一样
- 检查约束(Check):对该列数据的范围、格式的限制(如:年龄、性别),例如 对年龄加以限定 20-40岁之间
- 默认约束(Default):该数据的默认值,例如 如果地址不填 默认为“地址不详”
- 外键约束(Foreign Key):需要建立两表间的关系,例如 建立外键
Django之深入了解ORM的更多相关文章
- python 全栈开发,Day70(模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介)
昨日内容回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...
- {Django基础六之ORM中的锁和事务}一 锁 二 事务
Django基础六之ORM中的锁和事务 本节目录 一 锁 二 事务 一 锁 行级锁 select_for_update(nowait=False, skip_locked=False) #注意必须用在 ...
- Django基础(2)--模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介
没整理完 昨日回顾: 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 ...
- day 71 Django基础六之ORM中的锁和事务
Django基础六之ORM中的锁和事务 本节目录 一 锁 二 事务 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 锁 行级锁 select_for_update(no ...
- Django模型层之ORM
Django模型层之ORM操作 一 ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...
- day 58 Django基础六之ORM中的锁和事务
Django基础六之ORM中的锁和事务 本节目录 一 锁 二 事务 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 锁 行级锁 select_for_update( ...
- Django框架之数据库ORM框架
首先,我来介绍一下什么是ORM框架: O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思.在ORM框架中,它帮 ...
- 【Django】--Models 和ORM以及admin配置
Models 数据库的配置 1 django默认支持sqlite,mysql, oracle,postgresql数据库 <1>sqlite django默认使用sqlite的数据库 ...
- Django 源码小剖: Django 对象关系映射(ORM)
引 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django O ...
- Django(四) ORM 外键操作及初识Ajax
一.内容回顾 1.Django请求的生命周期: 路由系统 -> 视图函数(获取模板+数据 -> 渲染) -> 字符串返回给用户 2.路由系统: /index/ #-> 函数 ...
随机推荐
- 第一章:Lambda表达式入门概念
要点:将行为像数据一样传递. 一.几种形式 1.没有参数,用()表示 () ->System.out.println("Hello World"); 2.有且仅有一个参数,省 ...
- 使用SDK方式进行微信授权
1.在pom.xml中添加依赖 <dependency> <groupId>com.github.binarywang</groupId> <artifact ...
- SparkStreaming整合Flume的pull方式之启动报错解决方案
Flume配置文件: simple-agent.sources = netcat-source simple-agent.sinks = spark-sink simple-agent.channel ...
- Restoring Road Network Floyd
问题 C: Restoring Road Network 时间限制: 1 Sec 内存限制: 128 MB提交: 731 解决: 149[提交] [状态] [讨论版] [命题人:admin] 题目 ...
- MD5/SHA1/Hmac_SHA1
1.MD5 #import <CommonCrypto/CommonDigest.h> + (NSString *) md5:(NSString *) input { const char ...
- nodejs入门安装与调试,mac环境
install nvm (node version manager) 安装nvm curl -o- https://raw.githubusercontent.com/creationix/nvm/v ...
- 深度探索C++对象模型之第一章:关于对象之C++对象模型
一.C和C++对比: C语言的Point3d: 数据成员定义在结构体之内,存在一组各个以功能为导向的函数中,共同处理外部的数据. typedef struct point3d { float x; f ...
- BlueHost主机建站方案怎样选择?
BlueHost是知名美国主机商,近年来BlueHost不断加强中国市场客户的用户体验,提供多种主机租用方案,基本能够满足各类网站建设需求.下面就和大家介绍一下建站应该怎样选择主机. 1.中小型网站 ...
- CSIC_716_20191118【常用模块的用法 Json、pickle、collections、openpyxl】
序列化模块 序列化:将python或其他语言中的数据类型,转变成字符串类型. python中的八大数据类型回顾:int float str list tuple dict set bool 反序列化: ...
- css----less预处理器
###less less是一种动态样式语言,属于css预处理器的范畴,它扩展了 CSS 语言, 增加了变量.Mixin.函数等特性,使 CSS 更易维护和扩展 LESS 既可以在 客户端 上运行 ,也 ...