ORM
一、ORM简介
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术,简单的说:ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
ORM在业务逻辑层和数据库层之间充当了桥梁的作用
二、Django中的ORM
2.1、Django连接MySql
在Django项目的settings.py文件中,配置数据库连接信息
DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "你的数据库名称", # 需要自己手动创建数据库 "USER": "数据库用户名", "PASSWORD": "数据库密码", "HOST": "数据库IP", "POST": 3306 } } #django默认使用sqllite DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
在Django项目的__init__.py文件中写如下代码,告诉Django使用pymysql模块连接MySQL数据库
import mysqldb pymysql.install_as_MySQLdb()
2.2、快速入门
在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表
基本情况:
- 每个模型都是一个Python类,它是django.db.models.Model的子类。
- 模型的每个属性都代表一个数据库字段。
- 综上所述,Django为您提供了一个自动生成的数据库访问API,,详询官方文档链接。
示例:
from django.db import models class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64)
初始化操作:
#setings文件注册新建的APP INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'host', #新建的 ] #在winds cmd或者Linux shell模式的django项目的manage.py目录下执行: python manage.py makemigrations #根据app下的migrations目录中的记录,检测当前model层代码是否发生变化? python manage.py migrate #把orm代码转换成sql语句去数据库执行
2.3、常用字段及字段参数
- AutoField(int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列)
- IntegerField(一个整数类型,范围在 -2147483648 to 2147483647)
- CharField(字符类型,必须提供max_length参数, max_length表示字符长度)
- DateField(日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例)
- DateTimeField(日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例)
字段参数:null(用于表示某个字段可以为空),unique(如果设置为unique=True 则该字段在此表中必须是唯一的),db_index(如果db_index=True 则代表着为此字段设置数据库索引),choices (Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操)
#models chang_stu = ((0, "上线"), (1, "下线")) status= models.IntegerField(verbose_name="状态",choices=chang_stu,default=1) #view pic = models.pic.objects.filter(status=0).order_by("-weight")[:3]
补充时间字段参数:配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库,配置上auto_now=True,每次更新数据记录的时候会更新该字段
2.4、关系字段
ForeignKey(外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方)字段参数:to(设置要关联的表)to_field(设置要关联的表的字段)on_delete(当删除关联表中的数据时,当前表与其关联的行的行为)
例如:usergg = models.ForeignKey("usergg",to_field='uid',on_delete=models.CASCADE) 或者直接usergg = models.ForeignKey("usergg")会默认对应到usergg表的主键
models.CASCADE 删除关联数据,与之关联也删除 models.DO_NOTHING 删除关联数据,引发错误IntegrityError models.PROTECT 删除关联数据,引发错误ProtectedError models.SET_NULL 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) models.SET_DEFAULT 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
2.5、简单的增、删、改、查
from cmdb import models def orm(request): #增加,方式一 models.USER.objects.create(username='xx',pw='xx') #方式二 obj=models.USER(username='xx',pw='xx') obj.save() #查询 r = mode.USER.objects.all() for i in r: print(i.id,i.username,i.pw) #根据条件筛选查询 mode.USER.objects.filter(username="xx" ) #删除 mode.USER.objects.filter(username="xx").delete() # 更新 mode.USER.objects.all() .update(username="x") mode.USER.objects.filter(username="x").update(username="xxx")
简单的筛选条件:
id__gt=1,id__lt=1 #大于、小于 id__gte=1 #大于等于 id__lte=1 #小于等于
id__icontains 不区分大小写 id__in=[1,2,3] #id在列表中 id__range=[1,2] # id范围是1到3的 id__startswith="xxx" #判断某个字段的值是否是以某个值开始的,还有endswith exclude(id=1) #不等于 order_by() "-id" #减号从大到小 name__contains="要查的模糊字段" #判断某个字段是否包含了某个数据 all() #查询所有结果 filter(**kwargs) #它包含了与所给筛选条件相匹配的对象 get(**kwargs) # 如果符合筛选条件的对象超过一个或者没有都会抛出错误 values(*field) #返回一个可迭代的字典序列 values_list(*field) #它与values()非常相似,它返回的是一个元组序列, reverse() #对查询结果反向排序,(调用order_by()方法后生效)。 distinct() #从返回结果中剔除重复纪录(使用distinct(),注意只有在PostgreSQL中支持按字段去重) count() # 返回数据库中匹配查询(QuerySet)的对象数量 first() #返回第一条记录 last() #返回最后一条记录 exists() #如果QuerySet包含数据,就返回True,否则返回False
2.5、ForeignKey联表操作
from django.db import models class UserType(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): name = models.CharField(max_length=16) age = models.IntegerField() ug = models.ForeignKey('UserType') #正查: v = UserInfo.objects.all().first() v.ug.title UserInfo.objects.values('id','ug_id','ug__title') UserInfo.objects.values_list('id','ug_id','ug__title') #反查: #1. 小写的表名_set obj = UserGroup.objects.all().first() obj.userinfo_set.all() obj.userinfo_set.filter(name='tim') #2. 小写的表名 v = UserGroup.objects.values('id','title','userinfo__age') v = UserGroup.objects.values_list('id','title','userinfo__age')
2.6、多对多 ManyToManyField
class Classes(models.Model): titile = models.CharField(max_length=32) m = models.ManyToManyField('Teachers',related_name='dddd') class Teachers(models.Model): name = models.CharField (max_length=32) obj = models.Classes.objects.filter(id=1).first() obj.m.add(3) #正加 obj = models.Teachers.objects.filter(id=2).first() obj.dddd.set([1,2]) #反加 obj.set("xxx")更新model对象的关联对象,obj.remove() 删除 #正查 v = models.Classes.objects.all().values('id','titile','m','m__name') print(v) #反查 v = models.Teachers.objects.all().values('name','dddd__titile') print(v)
#或者自定义第三张表,通过foreignkey class host(models.Model): nid = models.AutoField(primary_key=True) hostname=models.CharField(max_length=64) ip = models.GenericIPAddressField(max_length=64) port = models.IntegerField() class application(models.Model): name= models.CharField(max_length=64) class hostapp(models.Model): hid = models.ForeignKey("host",to_field="nid",on_delete=models.CASCADE) aid = models.ForeignKey("application",to_field="id",on_delete=models.CASCADE)
2.7、分组与聚合
from django.db.models import Avg,Min,Sum,Max,Count,F,Q 聚合查询(aggregate) models.book.objects.all().aggregate(Avg("price")) 求平均值 models.book.objects.all().aggregate(Sum("price")) 求和 models.book.objects.filter(book_au__name="li").aggregate(Sum("price")) #求作者li的书的总价 models.book.objects.filter(book_au__name="li").aggregate(Count("price")) #求作者li的书的数量 分组查询(annotate) models.book.objects.values('book_au__name').annotate(Sun("price")) #求每一个作者出书的总价格 models.au.objects.values("name").annotate(Min("book__price")) #求每个出版社出的最便宜的书价格
2.8、F查询和Q查询
from django.db.models import Avg,Min,Sum,Max,Count,F,Q #F查询 models.book.objects.all().update(price=F("price")+10) #每本书加10元(自增) models.Book.objects.filter(commnet_num__gt=F('keep_num')) #查询评论数大于收藏数的书 #Q查询 models.book.objects.filter(Q(price=99)|Q(name="java")) #(|为or) (& 为and) models.book.objects.filter(~Q(name="java")) #非 (除了name为java的)
补充:组合搜索
q1 = Q() q1.connectro = "AND" q1.childeren.append(("id",1)) q2 = Q() q2.connectro = "OR" q1.childeren.append(("id",2)) con=Q() con.add(q1,"AND") con.add(q2,"AND") models.Tb1.objects.filter(con) k = {"k1":1,"k2":2} con = Q() for k,v in k.items() q=Q() q.connectro="OR" for i in v: q.childeren.append(("id",v)) con.add(q,"AND")
2.9、补充
models.UserInfo.objects.only("id","name") #仅取某个表中的数据 models.UserInfo.objects.defer('username','id') #defer,排除某列数据 models.UserInfo.objects.all.using("dbname") #指定去哪个数据库拿数据 select_related("foreignkey name") #联表查询 models.UserInfo.objects.all.select_related("id") #主动联表,减少后面循环取值,减少sql查询次数 prefetch_related() #不做联表,多次单表查询 objs = [models.UserInfo(name='r11'),models.UserInfo(name='r12') ] models.UserInfo.objects.bulk_create(obj,10)#批量增加,一次增加10个 models.UserInfo.objects.get_or_create(username="xxx",default={'email': '11','u_id': 2, 't_id': 2})}) #如果有就获取,没有就增加default的内容 .update_or_create(同上) #如果有就更新,没有就创建 models.UserInfo.objects.in_bulk([1,2,3]) # 根据主键ID进行查找 # 将获取的到列名转换为指定列名 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} models.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 执行原生SQL models.UserInfo.objects.raw('select * from userinfo') #extra (额外的查询条件) models.UserInfo.objects.all().extra(select={ 'n':"select count(1) from app01_usertype where id=%s or id=%s", 'm':"select count(1) from app01_usertype where id=%s or id=%s",}, select_params=[1,2,3,4]) #占位符按顺序排 models.UserInfo.objects.extra(where=["id=1 or id=%s ","name=%s"],params=[1,"sb"] ) #where
2.10、元信息
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: #ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名 db_table = "table_name" # 联合索引 index_together = [ ("pub_date", "deadline"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称 verbose_name # verbose_name加s verbose_name_plural