ORM表操作
一、ORM配置
1.1 配置mysql数据库连接
setting文件里的DATABASES设置为
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'wangyong', ## 数据库名称 'USER': 'root', 'PASSWORD': '123', ## 安装 mysql数据库时,输入的root用户的密码 'HOST': '127.0.0.1', }
1.2 注册app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
1.3 设置pymysql连接(在任何的一个 __init__.py中都可以)
import pymysql pymysql.install_as_MySQLdb()
1.4 创建模型表(models.py)
class Class(models.Model): # id不用写, 自动生成 cname = models.CharField(max_length=32, null=True) class Students(models.Model): # id不用写, 自动生成 sname = models.CharField(max_length=32, null=True) class_id_cname = models.ForeignKey('Class', null=True, on_delete=models.SET_NULL) class Teachers(models.Model): tname = models.CharField(max_length=32, null=True) class Teacheres_Classes(models.Model): id = models.AutoField(primary_key=True) cid_cname = models.ForeignKey('Class', null=True) tid_tname = models.ForeignKey('Teachers', null=True) class Meta: unique_together = (('cid_cname', 'tid_tname'),)class BaseModel(models.Model): """公共模型""" orders = models.IntegerField(verbose_name='显示顺序') is_show = models.BooleanField(verbose_name="是否上架", default=False) is_delete = models.BooleanField(verbose_name="逻辑删除", default=False) created_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True, null=True, blank=True) updated_time = models.DateTimeField(verbose_name="更新时间", auto_now=True, null=True, blank=True) class Meta: # 抽象模型,一般用于设置公共模型字段的,一旦设置这个相关以后,那么dajngo在数据迁移的时候就不会为这个模型单独创建一个数据表了 abstract=True
1.5 生成表
1.5.1 方式一:快捷生成
1. 工具栏 Tools --> run manage.py Task
2. 在出现的manage.py@项目名称中依次输入
makemigrations
migrate
1.5.2 方式二:在Terminal中执行命令
python3 manage.py makemigrations ## 生成migrations文件 python3 manage.py migrate ### 根据生成的migrations文件生成表
二、对单表的操作
2.1 增
# 增加一条数据 Class.objects.create(name="xxx") # 增加会有一个返回值,这个返回值就是这次插入的对象 # 增加多条数据 obj = [ Class(cname='pyton111'), Class(cname='pyton222'), Class(cname='pyton333'), ] Class.objects.bulk_create(obj)
2.2 删除
models.Classes.objects.filter(name="xxx").delete()
2.3 改
models.Classes.objects.filter(name="xxx").update(name="ooo") # 如果需要改的值很多,并且在一个字典里,也可以用**打散 models.Classes.objects.filter(name="xxx").update(**dic)
2.4 普通查询
# 1、查询所有 res = Class.objects.all() # QuerySet对象,(列表套对象) print(res) # <QuerySet [<Class: Class object>, <Class: Class object>, <Class: Class object>, <Class: Class object>]> for row in res: print(row.id, row.cname) # 2. 指定字段查询 values, value_list res = Class.objects.values('cname').all() # QuerySet对象,(列表套字典) print(res) res = Class.objects.values_list('cname').all() # QuerySet对象,(列表套元组) print(res) # 3、filter 筛选 res = Class.objects.filter(id=1).all() print(res) # <QuerySet [<Class: Class object>] # 4、大于,大于等于,小于,小于等于 __gt, __gte, __lt, __lte res = Class.objects.filter(id__lt=3) print(res) # <QuerySet [<Class: Class object>, <Class: Class object>]> for row in res: print(row.id, row.cname)
2.5 高级查询
# 1、in res = Class.objects.filter(id__in = [1,2,3]) print(res) # <QuerySet [<Class: Class object>, <Class: Class object>, <Class: Class object>]> for row in res: print(row.id, row.cname) # 2、 not in res = Class.objects.exclude(id__in=[1,2,3]) print(res) # <QuerySet [<Class: Class object>]> for row in res: print(row.id, row.cname) # 3、like # startswith, istartwith,(不区分大小写) where name like 'py%' ## 以py开头的所有的数据 # endswith, iendswith where name like '%py' # contains, icontains 包含某一个单词 where name like "%py%" res = Class.objects.filter(cname__istartswith='py') print(res) # <QuerySet [<Class: Class object>, <Class: Class object>, <Class: Class object>, <Class: Class object>]> for row in res: print(row.id, row.cname) # 4、between ... and .. res = Class.objects.filter(id__range=[1,3]) print(res) # <QuerySet [<Class: Class object>, <Class: Class object>, <Class: Class object>]> # 5、limit 10,20 res = Class.objects.all()[0:3] #[ 开始位置: 结束位置] print(res) # <QuerySet [<Class: Class object>, <Class: Class object>, <Class: Class object>]> # 6、order by age asc, name desc res = Class.objects.all().order_by('id', 'cname') # 默认升序前面加一个 ‘-’ 代表 降序 print(res.query) # SELECT "app1_class"."id", "app1_class"."cname" FROM "app1_class" ORDER BY "app1_class"."id" ASC, "app1_class"."cname" ASC # 7、group by from django.db.models import Count, Max, Min, Sum res = Class.objects.values('cname').annotate(xxx=Count('id')) print(res.query) # SELECT "app1_class"."cname", COUNT("app1_class"."id") AS "xxx" FROM "app1_class" GROUP BY "app1_class"."cname" # 8、only: 只取某一列值 res = Class.objects.only('id', 'cname').all() print(res.query) # SELECT "app1_class"."id", "app1_class"."cname" FROM "app1_class" # 9、defer: 除了这几列之外的所有值 (但是不管怎样, 都会查 id) res = Students.objects.defer('id','sname').all() print(res.query) # SELECT "app1_students"."id", "app1_students"."stu_cla_id" FROM "app1_students" # 10、 using: 想要使用哪个数据库, 就将这个数据库的配置名称写到using中 Class.objects.all().using('xxxx') # 11、count 表中总共有多少条数据 res = Class.objects.count() # count不需要参数 print(res) # 12、第一条数据,最后一条数据 res = Class.objects.first() ret = Class.objects.last() print(res, ret) # Class object Class object # 13、 gt 大于 gte: 大于等于 lt 小于 lte 小于等于 res = Class.objects.filter(id__gt=2) print(res) # <QuerySet [<Class: Class object>, <Class: Class object>]> # 14、and操作 res = Class.objects.filter(id=1,cname='pyton111') print(res) # <QuerySet [<Class: Class object>]> print(res.query) # SELECT "app1_class"."id", "app1_class"."cname" FROM "app1_class" WHERE ("app1_class"."id" = 1 AND "app1_class"."cname" = pyton8期) # 15、or操作 from django.db.models import Q res = Class.objects.filter(Q(id=2) | Q(cname='pyton111')) print(res.query) # SELECT "app1_class"."id", "app1_class"."cname" FROM "app1_class" WHERE ("app1_class"."id" = 2 OR "app1_class"."cname" = pyton8期) # 16、在原来的基础上更新值 from django.db.models import F UserInfo.objects.update(age=F('age') + 1) # 表中存在可以需要更新的值,使用方式如此 # 17、原生sql # 方式一 from django.db import connection cursor = connection.cursor() cursor.execute("select * from app1_class where id=%s", [1,]) res = cursor.fetchall() print(res) # res = cursor.fetchone() print(res) # 方式二 res= Class.objects.raw('select * from main.app1_class') print(res) # <RawQuerySet: select * from main.app1_class> for row in res: print(row.id, row.cname)
三、一对多操作
3.1 查
# 1、查询所有 res = Students.objects.all() # 列表套对象 print(res) # <QuerySet [<Students: Students object>, <Students: Students object>]> # 2、查询一个 res = Students.objects.first() print(res) # Students object print(res.id, res.sname, res.stu_cla_id) # 1 富强 1 # 3、正向查询 res = Students.objects.all() for row in res: print(row.id, row.sname, row.stu_cla.cname) # 4、 反向查询 外键关联的表名小写_set.filter() # 需求:查询所有课程下的所有学生姓名 res = Class.objects.all() for row in res: print(row.cname, row.students_set.all()) for k in row.students_set.all(): print(row.cname, k.sname) # 5、神奇的双下划线(跨表查询) (列表套字典) res = Students.objects.values('sname', 'stu_cla__cname') print(res)
四、多对多操作
4.1 查
# 查询 老师 zeikai 所教的班级 # 方式一 res = Teachers.objects.filter(sname='zekai').first() print(res.id, res.sname) # 1 zekai tea_cla_list = res.teacherclass_set.all() print('tea_cla_list',tea_cla_list) # <QuerySet [<TeacherClass: TeacherClass object>, <TeacherClass: TeacherClass object>]> for obj in tea_cla_list: print(obj.cid.cname) # 方式二 res = TeacherClass.objects.filter(tid__sname='zekai').all() for obj in res: print(obj.cid.cname) # 方式三 res = TeacherClass.objects.filter(tid__sname='zekai').values('cid__cname') print(res)
五、ORM的列数据类型
六、ORM中的参数
6.1 基础参数
max_length=32 null=True : # 可以设置为null db_index=True : # 设置索引 on_delete=models.CASCADE # 设置级联删除 SET_NULL : # 取消级联删除 default : # 设置默认值 unique : # 设置唯一索引 db_column: # 设置一个列名 unique_together: 联合唯一索引 index_together :普通联合索引 class Meta: unique_together = ( ('money', 'us_id'), .... ) index_together = ( ('money', '') .... )
""" 1、外键位置: 一对多 - 外键放多的一方 一对一 - 从逻辑正反向考虑,如作者表与作者详情表,作者删除级联删除详情,详情删除作者依旧存在,所以建议外键在详情表中 多对多 - 外键在关系表中 2.关联表之间断关系(全部写在外键字段的括号里) db_constraint=False, # 断关联 related_name='books', # 反向查询字段:publish_obj.books 就能访问所有出版的书(名字可随意取) 2、ORM正向方向连表查找: 正向:通过外键字段 eg: author_detial_obj.author 反向:通过related_name的值 eg:author_obj.detail 注:依赖代码见下方 3、连表操作级联关系(以作者表和详情表(外键在此表)一对一为例,写在外键字段括号里): 1)级联删除:(作者删除,详情也删除);(详情删除,作者不删除) - on_delete=models.CASCADE 2)作者删除,详情表外键字段值置空其他字段值不变 - null=True, on_delete=models.SET_NULL 3)作者删除,详情表外键字段值重置为默认值 - default=0, on_delete=models.SET_DEFAULT 4)作者删除,详情表对应那一整条信息不动 - on_delete=models.DO_NOTHING 注:拿作者与作者详情表举例 4、外键关联字段的参数 - 如何实现 断关联、目前表间操作关系、方向查询字段 i)作者详情表中的 author = models.OneToOneField( to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE ) ii)图书表中的 publish = models.ForeignKey( to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING, ) authors = models.ManyToManyField( to='Author' related_name='books', db_constraint=False, ) 注:ManyToManyField不能设置on_delete,OneToOneField、ForeignKey必须设置on_delete(django1.x系统默认级联,但是django2.x必须手动明确) """
七、如何扩张auth_user表
7.1 一对一关联(不推荐)
from django.contrib.auth.models import User class UserDetail(models.Models): phone = models.CharField(max_length=11) user = models.OnoToOneField(to=User)
7.2 面向对象继承
from django.contrib.auth.models import User,AbstractUser class UserInfo(AbstractUser): phone = models.CharField(max_length=32) # 在settings中需要在配置文件中,指定我不再使用默认的auth_user表而是使用我自己创建的Userinfo表 AUTH_USER_MODEL = "app名.models里面对应的模型表名"
八、ORM的自关联