django的orm操作

写该篇博客的原因

目前在学习django,django的orm非常好用,但是网上找的orm的操作写的普遍不是很全面,找了几篇都不是很清晰,所以自己整理一下(多对多后面会更新)

单表数据库模型

# 这个类在models.py(模型)文件中
class Users(models.Model):
	SEX = ((0,'man'),(1,'woman'))
	# 后面sex字段会用到这个
	id = models.AutoField(primary_key=True) 
	# 不加这个id字段的话就会自己生成一个自增主键,字段名也是id,所以这个字段可写可不写
	name = models.CharField(max_length=50, blank=True, null=True, verbose_name='姓名')
	# verbose_name属性就是admin后台管理显示的字段名,如果不加的话,admin后台默认就是英文的字段(name)
	# 注意null和blank的区别: null=True表示在数据库层面可为空,而blank=True则是在django层面限制可为空,使用时两者是连用的,否则数据库可空但django不能为空,还是会报错的,反之亦然
	age = models.IntegerField(blank=True, null=True, verbose_name='年龄')
	phone = models.CharField(max_length=11, default='', blank=True, verbose_name='手机号')
	# blank=True,就是表单可为空,所以数据表该字段给一个 default='' ,表示该字段默认为空
	sex = models.CharField(max_length=50, blank=True, null=True, verbose_name='性别', choices=Sex)
	# choices属性是‘选择’属性,存0就代表男,存1就代表女,admin后台管理页面就显示一个下拉框,让用户选择男女,选完之后按照0,1存数据库中。可以用obj.get_字段名称_display拿到0,1对应的‘男’,‘女’。
	
	def __str__(self):
        return self.name
	class Meta:
		db_table = 'users' # 在数据库中的表名
		ordering = ['-age', 'name'] # 年龄倒叙,名字正序,排序会增加数据库负担
		

# 下面的语句写在views.py(视图)文件中
# 从模型文件models.py中导入所有的模型类
from models import *
# 增加有以下几种方法

# 方法一:
obj = Users()
obj.name  = 'make'
obj.age = 18
....
obj.save() # 一定要执行save否则不会执行插入数据操作

# 方法二:
obj = Users(name="make",age=18,phone='133-8888-6666',sex=0)
obj.save() 

# 方法三:
Users.objects.create(name="make",age=18,phone='133-8888-6666',sex=0)
# obj = Users.objects.create(name="make",age=18,phone='133-8888-6666',sex=0)
# create添加数据后会返回插入数据的类对象(存到了上面的obj变量中),通过这个类对象.属性(obj.name) 可以获取到对应字段的数据

# 方法四:
# 在管理器类中自己定义创建方方法:
# 创建一个自己的管理器,继承models.Manager
class myManager(models.Manager):
	# 重写get_queryset方法,可以让返回的QuerySet(原始查询集)只包含sex=0(性别为男)的数据,所有基于QuerySet的查询方法都会被影响,例如.all(), .filter()...
	def get_queryset(self):
		return super().get_queryset().filter(sex=0)
		
	# 也可以只重写某方法,例如重写all,可以让.all()方法在查询时只获得sex=0(性别为男)的数据
	def all(self):
        return super().all().filter(sex=0)

# 继承自己的管理器,定义了一个自己的管理器的create方法
class UsersManager(myManager):
	def create(self,name,age,phone,sex):
		obj = self.model()
		obj.name = name
		obj.age = age
		obj.phone = phone
		obj.sex = sex
		return obj

# 把objects从默认的Manager()改成自己的UserManager()管理器
class Users(models.Model):
	objects = UserManager()

# Users用create创建的时候可以不用以关键字参数传参了
obj = Users.objects.create('make',18,'133-8888-6666',0)
obj.save()

# 方法五:
# 在模型类(Users)中定义一个类方法用于创建对象
@classmethod
def create(cls, name, age, phone, sex):
	return cls(name=name, phone=phone, sex=sex)

obj = Users.create('make',18,'133-8888-6666', 0)
obj.save()
	

在开查询之前,首先了解几个名词:

  1. 查询集:从数据库中获取数据的集合
  2. 原始查询集:调用get_queryset得到的查询集,不作为数据的提取
  3. 数据查询集合:在原始查询集或查询集上调用过滤器得到的数据查询集
  4. 过滤器:过滤器有返回查询集的过滤器,还有返回单个值得过滤器,见下方代码块注释。过滤器可以使用链式语法:Users.objects.all().filter().filter()
# 返回查询集的过滤器:all(), filter(), exclude(), older_by(), values()...
# 返回单个值得过滤器:get(), count(), first(), last(), exists()...

# all获取全部数据
uses = Users.objects.all()
# filter获取符合条件的全部数据,有两种写法
users = Users.objects.all().filter(name='make', age=18)
users = Users.objects.all().filter(name='make').filter(age=18)
# exclude返回不包含条件的数据集
users = Users.object.all().exclude(age=18) # 返回的结果集中不包括age=18的
# older_by根据字段进行排序
users = Users.objects.all().order_by('age') # 升序
users = Users.objects.all().order_by('-age') # 降序
# valuse一个对象是一个字典,构成一个列表返回
users = User.objects.values()
# values_list一个对象是一个元组,构成一个列表返回
users = User.objects.values_list()
# get获取单个满足条件的对象,如果没找到,则报 模型类.DoesNotExist异常,如果多条被返回则报 模型类.MultipleObjectsReturned, 均可通过try except捕获
user = Users.object.get(name='make')
# count返回查询集中的数据数量
user_num = Users.objects.all().count()
# first返回查询集中第一个对象
user = Users.objects.all().first()
# last返回查询集中最后一个对象
user = Users.objects.all.last()
# exists判断数据集中是否有数据,有返回True, 没有返回False
user_num = Users.objects.all().exists()

# 字段查询:实现where子句,作为filter,get等方法的参数
# 语法:属性名__比较运算符=值
# 对于外键:需要使用 外键属性_id 表示外键
# % 的使用:sql语句:where name like '%\%%'  ===>  orm语句: filter(name__contains='%')
# 比较运算符都有哪些:exact, contains, startswith, endswith, iexact, icontains, istartswith, iendswith, isnull, isnotnull, in, gt, gte, lt, lte, year, month, day, week_day, hour, minute, second...

# 改的三种方法
# 方法一: objects调用,下面示例是整列数据更新
Users.objects.update(name='make', age=18...)

# 方法二: queryset类型数据调用,下面也是更新整列数据
Users.objects.all().update(name='make', age=18...)

# 方法三:queryset类型数据调用,更新部分记录数据
obj = Book.objects.filter(name='make').update(name='bob')
print(obj) # 2 返回结果为受影响的行数

# 模型类对象不能直接调用update方法,错误示例如下
Users.objects.get(id=1).update(name='make')
# 报错信息'Book' object has no attribute 'update'

# delete()调用者可以是model对象,也可以是QuerySet类型数据
obj = Users.objects.get(id=3).delete()
print(obj) # (1, {'app01.Book': 1})

# 返回结果其实还是受影响的行数

obj = Users.objects.filter(name='make').delete()
print(obj)  # (2, {'app01.Book': 2})
    
# 错误示例演示
obj = Users.objects.delete()
# 报错'Manager' object has no attribute 'delete'
# 控制器没有delete方法,原因就是怕你一下子全部删除了所有数据

动态操作

# 更新或创建,有就更新,没有就添加update_or_create()
Users.objects.update_or_create(
	id=1,
    defaults={
        'name': 'make',
        'age': 18
	}
)
# 查询或创建,能够查询到就返回查询结果,查询不到就添加记录,查询时内部使用的还是get方法
Users.objects.get_or_create(
	id=1,
    defaults={
        'name': 'make',
        'age': 18
	}
)

多表

一对一(OneToOne)数据库模型

# 声明关系的表为从表,OneToOne在哪张表声明都可以
# 一对一应用场景: 
# 1. 一个用户对应一张身份证, 而身份证的信息不常用, 这个时候就可以将 " 身份证的信息抽取出来称为另一张表", 使两张表进行一对一的关联
# 2. 已经有一张表,想在不改变原表基础上增加新字段,也可以用一对一关联

class IdCard(models.Model):
	idnum = models.CharField(max_lenght=20)
	sex = models.BoolearnField()
	class Meta:
		db_table='IdCard'
		
class People(models.Model):
	name = models.CharField(max_lenght=10)
	card = models.OneToOneField(to='IdCard',to_field='id',on_delete=models.CASCADE)
	# to 关联的表  to_field 关联的字段(默认关联那个表的id)  on_delete 级联删除
	class Meta:
		db_table='people'
		
# on_delete的级联删除模式:
# 1. models.CASCADE 默认的模式,删除主表数据,从表中的一个外键被删除,删除从表数据,主表数据不动。
# 2. models.PROTECT 保护模式,从表中有数据时候无法删除主表数据,删除从表数据时候主表数据不动
# 3. models.SET_NULL 空值模式
# 4. models.SET_DEFAULT 默认值模式
# 5. models.SET() 动态设置模式,删除时动态指向一个实体访问
	
# 先创建一个主表对象
mycard = IdCard.objects.create(idmum='220303199912302222',sex=0)
# 再创建从表对象
People.objects.create(name='make', card=mycard)
# 从(People)获取主(IdCard)
# 格式:从表对象.外键属性.主表属性
people = People.objects.get(id=1)
print(people.card.idnum)

# 主(IdCard)获取从(People)
# 格式:主表对象.从表模型类名小写.从表属性
card = IdCard.objects.get(id=1)
print(card.people.name)
# 主表的改法和单表的没区别
mycard = IdCard.objects.get('id'=1)
mycard.sex=1
mycard.save()

# 从表的改法:
mycard = IdCard.objects.create(idnum='220303199912302222', sex=1) # 主表对象 

# save()方法
people = People.objects.get(id=1)
people.name = 'make'
people.card = mycard # 从表对象.onetoone字段 = 主表对象
people.save()

# 注意:update()是QuerySet的方法
people_QS = People.objects.filter(name='make') # filter获得的从表对象是QuerySet类型
people_QS.update(name='bob', card=mycard)
# 删除的时候和单表没什么区别,直接删除就行,但是模式要看on_delete级联删除怎么设置的
People.objects.get(name='make').delete()
IdCard.objects.get(id=1).delete()
IdCard.objects.all().delete() # 清空一整张表

一对多/多对一(foreginkey)数据库模型

# 声明关系的表为从表,一对多的foreginkey写在多的那边,假如一个班级对应多个学生,那么foreginkey就写在学生表中,学生表就为从表
# related_name:反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。
# related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
class Grade(models.Model):
	grade_name = models.CharField(max_lenght=20)
	
	class Meta:
		db_table='grade'
		
class Students(models.Model):
	name = models.CharField(max_lenght=10)
	grade = models.ForeginKey(to='Grade',to_field='id',on_delete=models.CASCADE)
# 方法一 和一对一相同
grade_obj = models.Grade.objects.get(id=1) # 班级(主表)对象
models.Students.objects.create(name='make', grade=grade_obj)

# 方法二
models.Students.objects.create(name='make', grade_id=1)  # 外键字段_id 班级的id值)
# 从(Students)获取主(Grade)  ==> 正向查询
# 格式:从表对象.外键属性.主表属性
# 已知一个学生,获取该学生所在的班级
stu = Studens.objects.get(id=1)
print(stu.grade.grade_name)

# 主(Grade)获取从(Students)  ==> 反向查询
# 格式:主表对象.从表类模型小写_set.过滤器
# 已知一个班级,查班级下的全部学生
grade = Grade.objects.get(id=1)
stus = grade.students_set.all()
print(stus)


# 查到grade_name值为一年一班的id
grade = Grade.objects.fliter(grade_name="一年一班").values(id)
# 通过grade得到的id,去到Students中查到这个班级id对应的学生姓名
stus = Students.objects.filter(grade=grade).values("name")
# 和一对一没区别
grade = Grade.objects.get('id'=1)
grade.grade_name='一年一班'
grade.save()

# 从表的改法:
grade = Grade.objects.create(grade_name='一年一班') # 主表对象 

# save()方法
stu = Students.objects.get(id=1)
stu.name = 'make'
stu.grade = grade # 从表对象.onetoone字段 = 主表对象
stu.save()

# 注意:update()是QuerySet的方法
students = Students.objects.filter(name='make') # filter获得的从表对象是QuerySet类型
students.update(name='bob', grade=grade)
# 和一对一的删除没区别
Grade.objects.get(name='一年一班').delete()
Students.objects.get(id=1).delete()
Students.objects.filter(name='make').delete()
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值