Django---ORM操作大全
Posted 听风。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django---ORM操作大全相关的知识,希望对你有一定的参考价值。
前言
Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 mysqldb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
ORM是什么?:(在django中,根据代码中的类自动生成数据库的表也叫--code first)
ORM:Object Relational Mapping(关系对象映射)
类名对应------》数据库中的表名
类属性对应---------》数据库里的字段
类实例对应---------》数据库表里的一行数据
obj.id obj.name.....类实例对象的属性
Django orm的优势:
Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可;
一、Django连接MySQL
1、创建数据库 (注意设置 数据的字符编码)
由于Django自带的orm是data_first类型的ORM,使用前必须先创建数据库
create database day70 default character set utf8 collate utf8_general_ci;
2、修改project中的settings.py文件中设置 连接 MySQL数据库(Django默认使用的是sqllite数据库)
DATABASES = { \'default\': { \'ENGINE\': \'django.db.backends.mysql\', \'NAME\':\'day70\', \'USER\': \'eric\', \'PASSWORD\': \'123123\', \'HOST\': \'192.168.182.128\', \'PORT\': \'3306\', } }
扩展:查看orm操作执行的原生SQL语句
在project中的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\', }, } }
3、修改project 中的__init__py 文件设置 Django默认连接MySQL的方式
import pymysql pymysql.install_as_MySQLdb()
4、setings文件注册APP
INSTALLED_APPS = [ \'django.contrib.admin\', \'django.contrib.auth\', \'django.contrib.contenttypes\', \'django.contrib.sessions\', \'django.contrib.messages\', \'django.contrib.staticfiles\', \'app01.apps.App01Config\', ]
5、models.py创建表
6、进行数据迁移
6.1、在winds cmd或者Linux shell的项目的manage.py目录下执行
python manage.py makemigrations
python manage.py migrate
扩展:修改表之后常见报错
这个报错:因为表创建好之后,新增字段没有设置默认值,或者原来表中字段设置了不能为空参数,修改后的表结构和目前的数据冲突导致;
二、modles.py创建表
ORM字段介绍
Djan提供了很多字段类型,比如URL/Email/IP/ 但是mysql数据没有这些类型,这类型存储到数据库上本质是字符串数据类型,其主要目的是为了封装底层SQL语句;
1、字符串类(以下都是在数据库中本质都是字符串数据类型,此类字段只是在Django自带的admin中生效)
name=models.CharField(max_length=32)
EmailField(CharField):
IPAddressField(Field)
URLField(CharField)
SlugField(CharField)
UUIDField(Field)
FilePathField(Field)
FileField(Field)
ImageField(FileField)
CommaSeparatedIntegerField(CharField)
扩展
models.CharField 对应的是MySQL的varchar数据类型
char 和 varchar的区别 :
char和varchar的共同点是存储数据的长度,不能 超过max_length限制,
不同点是varchar根据数据实际长度存储,char按指定max_length()存储数据;所有前者更节省硬盘空间;
2、时间字段
models.DateTimeField(null=True)
date=models.DateField()
3、数字字段
(max_digits=30,decimal_places=10)总长度30小数位 10位)
数字: num = models.IntegerField() num = models.FloatField() 浮点 price=models.DecimalField(max_digits=8,decimal_places=3) 精确浮点
4、枚举字段
choice=( (1,\'男人\'), (2,\'女人\'), (3,\'其他\') ) lover=models.IntegerField(choices=choice) #枚举类型
扩展
在数据库存储枚举类型,比外键有什么优势?
1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
2、在modle文件里不能动态增加(选项一成不变用Django的choice)
其他字段
db_index = True 表示设置索引 unique(唯一的意思) = True 设置唯一索引 联合唯一索引 class Meta: unique_together = ( (\'email\',\'ctime\'), ) 联合索引(不做限制) index_together = ( (\'email\',\'ctime\'), )
ManyToManyField(RelatedField) #多对多操作
字段参数介绍
1.数据库级别生效
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767 IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647 BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 自定义无符号整数字段 class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return \'integer UNSIGNED\' PS: 返回值为字段在数据库中的属性,Django字段默认的值为: \'AutoField\': \'integer AUTO_INCREMENT\', \'BigAutoField\': \'bigint AUTO_INCREMENT\', \'BinaryField\': \'longblob\', \'BooleanField\': \'bool\', \'CharField\': \'varchar(%(max_length)s)\', \'CommaSeparatedIntegerField\': \'varchar(%(max_length)s)\', \'DateField\': \'date\', \'DateTimeField\': \'datetime\', \'DecimalField\': \'numeric(%(max_digits)s, %(decimal_places)s)\', \'DurationField\': \'bigint\', \'FileField\': \'varchar(%(max_length)s)\', \'FilePathField\': \'varchar(%(max_length)s)\', \'FloatField\': \'double precision\', \'IntegerField\': \'integer\', \'BigIntegerField\': \'bigint\', \'IPAddressField\': \'char(15)\', \'GenericIPAddressField\': \'char(39)\', \'NullBooleanField\': \'bool\', \'OneToOneField\': \'integer\', \'PositiveIntegerField\': \'integer UNSIGNED\', \'PositiveSmallIntegerField\': \'smallint UNSIGNED\', \'SlugField\': \'varchar(%(max_length)s)\', \'SmallIntegerField\': \'smallint\', \'TextField\': \'longtext\', \'TimeField\': \'time\', \'UUIDField\': \'char(32)\', BooleanField(Field) - 布尔值类型 NullBooleanField(Field): - 可以为空的布尔值 CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度 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中提供验证 URL SlugField(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 上传图片的宽度保存的数据库字段名(字符串) DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) - 浮点型 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度 BinaryField(Field) - 二进制类型 字段
2、Django admin级别生效
针对 dango_admin生效的参数(正则匹配)(使用Django admin就需要关心以下参数!!))
blanke (是否为空) editable=False 是否允许编辑 help_text="提示信息"提示信息 choices=choice 提供下拉框 error_messages="错误信息" 错误信息 validators 自定义错误验证(列表类型),从而定制想要的验证规则 from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ \'c1\': \'优先错信息1\', \'c2\': \'优先错信息2\', \'c3\': \'优先错信息3\', }, validators=[ RegexValidator(regex=\'root_\\d+\', message=\'错误了\', code=\'c1\'), RegexValidator(regex=\'root_112233\\d+\', message=\'又错误了\', code=\'c2\'), EmailValidator(message=\'又错误了\', code=\'c3\'), ]
三、ORM单表操作
0、orm操作前戏
orm使用方式:
orm操作可以使用类实例化,obj.save的方式,也可以使用create()的形式
QuerySet数据类型介绍
QuerySet与惰性机制
所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。
QuerySet特点:
<1> 可迭代的
<2> 可切片
<3>惰性计算和缓存机制
def queryset(request): books=models.Book.objects.all()[:10] #切片 应用分页 books = models.Book.objects.all()[::2] book= models.Book.objects.all()[6] #索引 print(book.title) for obj in books: #可迭代 print(obj.title) books=models.Book.objects.all() #惰性计算--->等于一个生成器,不应用books不会执行任何SQL操作 # query_set缓存机制1次数据库查询结果query_set都会对应一块缓存,再次使用该query_set时,不会发生新的SQL操作; #这样减小了频繁操作数据库给数据库带来的压力; authors=models.Author.objects.all() for author in authors: print(author.name) print(\'-------------------------------------\') models.Author.objects.filter(id=1).update(name=\'张某\') for author in authors: print(author.name) #但是有时候取出来的数据量太大会撑爆缓存,可以使用迭代器优雅得解决这个问题; models.Publish.objects.all().iterator() return HttpResponse(\'OK\')
增加和查询操作
增
def orm(request): orm2添加一条记录的方法 单表 1、表.objects.create() models.Publish.objects.create(name=\'浙江出版社\',addr="浙江.杭州") models.Classify.objects.create(category=\'武侠\') models.Author.objects.create(name=\'金庸\',sex=\'男\',age=89,university=\'东吴大学\') 2、类实例化:obj=类(属性=XX) obj.save() obj=models.Author(name=\'吴承恩\',age=518,sex=\'男\',university=\'龙溪学院\') obj.save() 1对多 1、表.objects.create() models.Book.objects.create(title=\'笑傲江湖\',price=200,date=1968,classify_id=6, publish_id=6) 2、类实例化:obj=类(属性=X,外键=obj)obj.save() classify_obj=models.Classify.objects.get(category=\'武侠\') publish_obj=models.Publish.objects.get(name=\'河北出版社\') 注意以上获取得是和 book对象 向关联的(外键)的对象 book_obj=models.Book(title=\'西游记\',price=234,date=1556,classify=classify_obj,publish=publish_obj) book_obj.save() 多对多 如果两表之间存在双向1对N关系,就无法使用外键来描述其关系了; 只能使用多对多的方式,新增第三张表关系描述表; book=models.Book.objects.get(title=\'笑傲江湖\') author1=models.Author.objects.get(name=\'金庸\') author2=models.Author.objects.get(name=\'张根\') book.author.add(author1,author2) 书籍和作者是多对多关系, 切记:如果两表之间存在多对多关系,例如书籍相关的所有作者对象集合,作者也关联的所有书籍对象集合 book=models.Book.objects.get(title=\'西游记\') author=models.Author.objects.get(name=\'吴承恩\') author2 = models.Author.objects.get(name=\'张根\') book.author.add(author,author2) #add() 添加 #clear() 清空 #remove() 删除某个对象 return HttpResponse(\'OK\')
删
级联删除
为防止读者跑路,不再赘述!
改
# 修改方式1 update() models.Book.objects.filter(id=1).update(price=3) #修改方式2 obj.save() book_obj=models.Book.objects.get(id=1) book_obj.price=5 book_obj.save()
查
def ormquery(request): books=models.Book.objects.all() #------query_set对象集合 [对象1、对象2、.... ] books=models.Book.objects.filter(id__gt=2,price__lt=100) book=models.Book.objects.get(title__endswith=\'金\') #---------单个对象,没有找到会报错 book1 = models.Book.objects.filter(title__endswith=\'金\').first() book2 = models.Book.objects.filter(title__icontains=\'瓶\').last() books=models.Book.objects.values(\'title\',\'price\', #-------query_set字典集合 [{一条记录},{一条记录} ] \'publish__name\', \'date\', \'classify__category\', #切记 正向连表:外键字段___对应表字段 \'author__name\', #反向连表: 小写表名__对应表字段 \'author__sex\', #区别:正向 外键字段__,反向 小写表名__ \'author__age\', \'author__university\') books=models.Book.objects.values(\'title\',\'publish__name\').distinct() #exclude 按条件排除。。。 #distinct()去重, exits()查看数据是否存在? 返回 true 和false a=models.Book.objects.filter(title__icontains=\'金\'). return HttpResponse(\'OK\')
连表查询
反向连表查询: 1、通过object的形式反向连表, obj.小写表名_set.all() publish=models.Publish.objects.filter(name__contains=\'湖南\').first() books=publish.book_set.all() for book in books: print(book.title) 通过object的形式反向绑定外键关系 authorobj = models.Author.objects.filter(id=1).first() objects = models.Book.objects.all() authorobj.book_set.add(*objects) authorobj.save() 2、通过values双下滑线的形式,objs.values("小写表名__字段") 注意对象集合调用values(),正向查询是外键字段__XX,而反向是小写表名__YY看起来比较容易混淆; books=models.Publish.objects.filter(name__contains=\'湖南\').values(\'name\',\'book__title\') authors=models.Book.objects.filter(title__icontains=\'我的\').values(\'author__name\') print(authors) fifter()也支持__小写表名语法进行连表查询:在publish标查询 出版过《笑傲江湖》的出版社 publishs=models.Publish.objects.filter(book__title=\'笑傲江湖\').values(\'name\') print(publishs) 查询谁(哪位作者)出版过的书价格大于200元 authors=models.Author.objects.filter(book__price__gt=200).values(\'name\') print(authors) 通过外键字段正向连表查询,出版自保定的书籍; city=models.Book.objects.filter(publish__addr__icontains=\'保定\').values(\'title\') print(city)
1、基本操作
# 增 # # models.Tb1.objects.create(c1=\'xx\', c2=\'oo\') 增加一条数据,可以接受字典类型数据 **kwargs # obj = models.Tb1(c1=\'xx\', c2=\'oo\') # obj.save() 以上是关于Django---ORM操作大全的主要内容,如果未能解决你的问题,请参考以下文章