Django之ORM操作
ORM(Object Relational Mapping),对象关系模型,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.
优势:
提供了对数据库的映射关系,不用直接编写SQL,只需操作对象就能对数据库操作数据.
劣势:
会在一定程度上牺牲程序的执行效率.
ORM的操作是有限的,有些复杂的操作是完成不了的.
Model
在Django中model是你的数据的单一 明确的信息来源.它包含了你存储的数据的重要字段和行为.通常,一个模型(model)映射到一个数据库表.
基本情况:
每个模型都是一个Python类,他是django.db.models.Model的子类.
模型的每个属性都代表一个数据库字段.
Django提供了一个自动生成的数据库访问API.
字段
常用字段
AutoField
自增的整型字段,必填参数primary_key=True,则生成数据库的主键.无该字段时,Django自动创建.
一个model不能有两个AutoField字段.
IntegerField
一个整数类型.数值范围是 -2147483648 ~ 2147483647.(十位数,也就是说使用该字段无法表示手机号).
CharField
字符类型.必须提供max_length参数.max_length表示字符的长度.CharField对应的是SQL中的varchar数据类型,max_length的参数代表执行varchar的最大长度.
DateField
日期类型.日期格式为YYYY_MM_DD,相当于Python中的datetime.date的实例.
参数:
auto_now: 每次修改本条数据记录时,将本字段修改为当前日期时间.
auto_now_add: 新创建对象时自动添加当前日期时间.
auto_now和auto_now_add和default参数是互斥的,不能同时设置.
DateTimeField
日期时间字段,格式为YYYY_MM_DD HH:MM:[:ss[:uuuuuu]][TZ],相当于python中的datetime.datetime的实例.
其他字段类型
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
当model中没有自增列,则会自动创建一个名为id的列.
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767.
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
- 正整数 0~2147483647.
BigIntegerField(IntegerField):
- 长整型(有符号) -9223372036854775808~9223372036854775807
BooleanField(Field):
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值.
TextField(Field):
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制,也就是了不提供了一套正则规则.
IPAddressField(Field):
- 字符串类型,Django Admin以及ModelForm撞提供了验证IPV4机制.
GenericIPAddressField(Field):
- 字符串类型,Django Admin以及ModelForm中提供验证IPV4和IPV6的机制.
- 参数:
protocol,用于指定IPV4或IPV6,'both','ipv4','ipv6'
unpack_ipv4,如果指定为True,则输入::ffff:192.0.2.1时候,可以解析为192.0.2.1,开启此功能,需要protocol='both'
URLField(CharField):
字符串类型,Django Admin以及ModelForm中提供验证支持字母 数字 下划线 连接符(减号)
CommaSeparatedIntegerField(CharField):
- 字符串类型,格式必须为逗号分割线的数字
UUIDField(Field):
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field):
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path 文件夹路径
match=None 正则匹配
recursive=False 递归下面的文件夹
allow_files=True 允许文件
allow_folders=False 允许文件夹
FileField(Field):
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = " " 上传文件的保存路径
storage = None 存储组件,默认 django.core.files.storage.FileSystemStorage
ImageField(FileField):
- 字符串.路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认 django.core.files.storage.FileSystemStorage
width_field = None 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
TimeField(DateTimeField):
- 时间格式 HH:MM[:ss[:uuuuuu]]
DurationField(Field):
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timefelta类型
FloatField(Field):
- 浮点型
DecimalField(Field):
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field):
- 二进制类型
自定义字段
自定义一个二进制字段,以及django字段与数据库字段类型的对应关系.
1 class UnsignedIntegerField(models.IntegerField): 2 3 def db_type(self, connection): 4 5 return 'integer UNSIGNED' 6 7 # PS: 返回值为字段在数据库中的属性 8 # Django字段与数据库字段类型对应关系如下: 9 'AutoField': 'integer AUTO_INCREMENT', 10 'BigAutoField': 'bigint AUTO_INCREMENT', 11 'BinaryField': 'longblob', 12 'BooleanField': 'bool', 13 'CharField': 'varchar(%(max_length)s)', 14 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 15 'DateField': 'date', 16 'DateTimeField': 'datetime', 17 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 18 'DurationField': 'bigint', 19 'FileField': 'varchar(%(max_length)s)', 20 'FilePathField': 'varchar(%(max_length)s)', 21 'FloatField': 'double precision', 22 'IntegerField': 'integer', 23 'BigIntegerField': 'bigint', 24 'IPAddressField': 'char(15)', 25 'GenericIPAddressField': 'char(39)', 26 'NullBooleanField': 'bool', 27 'OneToOneField': 'integer', 28 'PositiveIntegerField': 'integer UNSIGNED', 29 'PositiveSmallIntegerField': 'smallint UNSIGNED', 30 'SlugField': 'varchar(%(max_length)s)', 31 'SmallIntegerField': 'smallint', 32 'TextField': 'longtext', 33 'TimeField': 'time', 34 'UUIDField': 'char(32)',
自定义一个char类型字段:
1 class MyCharField(models.Field): 2 """ 3 自定义的char类型的字段类 4 """ 5 def __init__(self, max_length, *args, **kwargs): 6 self.max_length = max_length 7 super(MyCharField, self).__init__(max_length = max_length, *args, **kwargs) 8 9 def db_type(self, connection): 10 """ 11 限定生成数据库表的字段类型为char,长度为max_length指定的值 12 """ 13 return 'char(%s)' % self.max_length
使用自定义char类型字段:
1 class Class(models.Model): 2 id = models.AutoField(primary_key=True) 3 title = models.CharField(max_length=25) 4 # 使用自己定义的char类型的字段 5 cname = MyCharField(max_length=25)
表结构:
字段参数
1 null 数据库中字段是否可以为空 2 db_column 数据库中字段的列名 3 default 数据库中字段的默认值 4 primary_key 数据库中字段是否为主键 5 db_index 数据库中字段是否可以建立索引 6 unique 数据库中字段是否可以建立唯一索引 7 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 8 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 9 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 10 11 verbose_name Admin中显示的字段名称 12 blank Admin中是否允许用户输入为空 13 editable Admin中是否可以编辑 14 help_text Admin中该字段的提示信息 15 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 16 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) 17 18 error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 19 字典健:null, blank, invalid, invalid_choice, unique, and unique 20 如:{'null': "不能为空.", 'invalid': '格式错误'} 21 22 validators 自定义错误验证(列表类型),从而定制想要的验证规则; 23 from django.core.validators import RegexValidator 24 from django.core.validators import EmailValidator,URLValidator,DecimalValidator,MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 25 如: 26 test = models.CharField( 27 28 max_length=32, 29 30 error_messages={ 31 32 'c1': '优先错信息1', 33 34 'c2': '优先错信息2', 35 36 'c3': '优先错信息3', 37 38 }, 39 40 validators=[ 41 42 RegexValidator(regex='root_\d+', message='错误了', code='c1'), 43 44 RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'), 45 46 EmailValidator(message='又错误了', code='c3'), ] 47 48 )
Model Meta参数及其功能
1 class UserInfo(models.Model): 2 nid = models.AutoField(primary_key=True) 3 username = models.CherField(max_length=32) 4 5 class Meta: 6 # 数据库中生成的表名,默认 app名称 + 下划线 + 小写类型 7 db_table = 'table_name' 8 9 # admin app01进去以后显示的表名称 10 verbose_name = '个人信息' 11 12 # verbose_name 加 s,admin app列表中显示的名称 13 verbose_name_plural = '所有用户信息' 14 15 # 联合索引 16 index_together = [ 17 ('pub_date', 'deadline'), # 应该为两个存在的字段 18 ] 19 20 # 联合唯一索引 21 unique_together = (('driver', 'restaurant'),) # 应给为两个存在的字段
在py文件中构造django查询环境
1 import os 2 3 if __name__ == "__main__": 4 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xxoo.settings") # xxoo.settings设置为自己实际的,可以去manage.py中查找. 5 import django 6 7 django.setup() 8 9 from ooxx import models # 设置为自己的app名
ORM操作
一般操作
必会部分:
all() 查询所有结果,最终的结果为QuerySet对象.
models.Press.objects.all() # 查询所有出版社
get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果只有一个,如果符合筛选条件的对象超过一个或者一个也没有,就会报错.最终结果为一个对象.
models.Press.objects.get(id=1) # 查询id等于1的出版社
filter(**kwargs) 它包含了与所给筛选条件相匹配的所有对象,最终返回结果为QuerySet对象.
models.Press.objects.filter(id=1) # 查询id等于1的所有出版社
exclude(**kwargs) 它包含了与所给筛选条件不匹配的所有对象,最终结果为QuerySet对象.
models.Press.objects.exclude(id=1) # 查询id不等于1的所有出版社
values(*field) 返回一个ValueQuerySet —— 一个特殊的QuerySet,运行后得到的并不是一些列的model的实例化对象。而是一个可迭代的字典序列。简单点说就是ValueQuerySet列表中包含着查询到的结果,每一个结果为一个字典,字典中键为*field字段,值为查到的结果。当*field不写时,查询到所有的字段。
models.Press.objects.all().values() # 查询所有对形象的所有字段,每条记录为一个字典 models.Press.objects.all().values('id', 'name') # 查询所有对象的id和name字段,每条记录为一个字典
values_list(*field) 与values()非常相似,区别就是他返回的是一个元祖序列.
models.Press.objects.all().values_list() # 查询所有对形象的所有字段,每条记录为一个元祖,顺序为values_list()中填写的字段的顺序 models.Press.objects.all().values_list('id', 'name') # 查询所有对象的id和name字段,每条记录为一个元祖,顺序为values_list()中填写的字段的顺序
order_by(*field) 对查询结果进行排序.最终的查询结果为QuerySet对象.当给*field前边加负号(-)时,按降序排序.
1 models.Press.objects.all().order_by('-id') # 查询结果按照id降序排列.结果为QuerySet对象. 2 3 models.Press.objects.all().order_by('age','-id') # 查询结果先按照age字段增序排列,出现相同age时再按照id降序排列.结果为QuerySet对象.
reverse() 对查询结果进行反序排序,请注意reverse()通常只能在具有已定义排序的QuerySet上调用(在model类的Meta中指定order_by()或者调用ordering方法.).
models.Person.objects.all().reverse()
distinct() 从返回结果中剔除重复记录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果.此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重.),返回结果为QuerySet对象.
count() 返回数据库中匹配查询(QuerySet)的对象数量.
models.Person.objects.all().count()
first() 返回第一条记录(对象),必须是返回结果为QuerySet时才能使用first()
models.Person.objects.all().first()
last() 返回最有一条记录(对象),必须是返回结果为QuerySet时才能使用last()
models.Person.objects.all().last()
exists() 如果QuerySet包含数据,就返回True,否则返回False.
models.Person.objects.all().exists()
单表查询值神奇的双下划线
字段名__gt greater than 大于
ret = models.Person.objects.filter(id__gt=1) # 查询id大于1的所有对象
字段名__lt less than 小于
ret = models.Person.objects.filter(id__lt=4) # 查询id小于4的所有对象
字段名__gte greater than equal 大于等于
ret = models.Person.objects.filter(id__gte=1) # 查询id大于等于1的所有对象
字段名__lte less than equal 小于等于
ret = models.Person.objects.filter(id__lte=1) # 查询id小于等于1的所有对象
字段名__in 在什么里
ret = models.Person.objects.filter(id__in=[1, 3]) # 查询id在列表里的所有对象
字段名__range=[条件1, 条件2]等价于 字段名__gte=条件1,字段名__lte=条件2,其中逗号(,)表示and关系.[条件1, 条件2]为闭区间.
ret = models.Person.objects.filter(id__gte=1, id__lte=3) # 查询id大于等于1,小于等于3的所有对象 ret = models.Person.objects.filter(id__range=[1, 3]) # 查询id在1到3之间的所有对象
字段名__contains='x' 模糊查找含有x的所有对象
ret = models.Person.objects.filter(name__contains='e') # 查询name中含有e的所有对象
字段名__icontains='x' 忽略大小写,模糊查找含有x的所有的对象
ret = models.Person.objects.filter(name__icontains='e') # 忽略大小,查找name中含有e的所有对象
字段名__startswith='o' 匹配以o开头的所有对象
ret = models.Person.objects.filter(name__startswith='e') # 匹配name中以e开头的所有对象
字段名__istartswith='o' 忽略大小写,匹配以o开头的所有对象
ret = models.Person.objects.filter(name__istartswith='e') # 忽略大小写,匹配name中以e开头的所有对象
字段名__endswith='x' 匹配以x结尾的所有对象
ret = models.Person.objects.filter(name__endswith='x') # 匹配name中以x结尾的所有对象
字段名__iendswith='x' 忽略大小写,匹配以x结尾的所有对象
ret = models.Person.objects.filter(name__iendswith='x') # 忽略大小写,匹配name中以x结尾的所有对象
date字段还可以:
models.Class.objects.filter(first_day__year=2017)