Django学习系列(二,Models数据操作篇)

Posted HUTEROX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django学习系列(二,Models数据操作篇)相关的知识,希望对你有一定的参考价值。

前言

通过昨天的学习学习了Django的项目结构,每个模块间的大致关系。在实际运行当中的关系逻辑,和在项目开始启动的配置问题。那么今天所学习的主要是关于Django对数据库的操作,如何使用好Models模块。这里主要介绍表的赋值和查询,因为其他的操作都是基于此的.

表的创建

表的简单创建

要想创建表,那么就必须先继承Model,这个其实是由于Django自己的一个数据处理方式,在Django当中所有的数据库操作都做了封装。

from django.db import models


class Student(models.Model):
    S_name = models.CharField(max_length=32)
    S_age = models.ImageField(default=1)

此时我们已经创建好了一个表。
但是我们在处理时还需要进行操作。

python manage.py makemigrations
python manage.py migrate

至于这是什么操作,我们得先来了解一下django对数据模型的处理。

Django的创建流程

在此之前我们先来看看Django对数据库处理这块的大致模式。

所以我们发现django之所以能够对数据库的操作做出封装,其实就是有一个处理机制,这个机制相当于翻译器,能够帮助我们把我们的操作,变成对应数据库的操作语言。
因此要想实现这个方案,那么就存在一个转换过程,和实际到数据库的操作过程。
而这个就是我们刚刚的

python manage.py makemigrations
python manage.py migrate

当执行第一条指令时,它生成了这样一个文件,里面写了这样一些东西。(这个其实昨天的博客有提到)


之后执行第二条指令,那么我们的表就创建好了。


但是这里注意的是,他这个名字并不是Student而是他自己又生成了一个名字,存在数据库里面。

“个性化”表的创建

对表字段的控制

db_colum              字段名
null                  False表示字段不可为空
blank                 False表示字段不可为空白
primary_key           设置为主键(默认会给你生成一个主键字段id,就像上面展示的表一样)
unqiue   			  是否为唯一

示例:

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	p_age = modeIntegerField(default=18)
	p_sex  = models.BooleanField(default=False)

这里注意一下,对应sql而言其实,只有几个类型字符串,数字,日期这几种。那个Boolean其实在django中是使用短整型来做的。这一点可以去查看它所生成的DDL。

改表名

这个也简单,看代码

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	p_age = modeIntegerField(default=18)
	p_sex  = models.BooleanField(default=False)
	class Meta:
		db_table = "Person"

但是请你注意一点,那就是无论是对表名进行修改还是对字段进行修改,其实都是修改的数据库里面的内容,当我们用代码进行控制时,还是以我们自己定义的类名,变量名来进行的!!!!!!

表的赋值

属性赋值法

这些方法是我自己定义命名的可能不准确.
这个是直接实例对象然后赋值,之后save()保存,上传到数据库的.

def set_value():
	person = Person()
	person.p_age=20
	person.p_name = "XiaoMing"
	person.save()

实例赋值法

这个就是在new(创建一个对象的时候直接传值)

person = Person(p_name="XiaoMing",p_age=20)
缺点就是在编写代码的时候IDE没有提示,而且容易搞错,且有Django版本兼容问题

自定义类方法赋值

我们来创建一个create()方法,在Person中

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	p_age = modeIntegerField(default=18)
	p_sex  = models.BooleanField(default=False)#0女1男
	class Meta:
		db_table = "Person"
	@classmethod
	def create(cls,p_name,p_age=18,p_sex=True):
		return cls(p_name=p_name,p_age=p_age,p_sex=p_sex)
	

这个cls其实就是我们的Person类
调用创建

Person = Person.create("XiaoMing")
Person.save()

数据过滤器(查询)

这里的话先简单分两大类,一个是返回满足条件的查询结果,一个是返回不满足条件的结果。
此外又可以细分为,返回多个结果的方法和返回一个的方法。此外我们还需要明白一点那就是所以的查询其实是通过objects来控制的,而这个其实是一个控制器,我们是可以自己指定的。

返回多结果的方法

all()		返回所有结果
filter()    返回满足条件的所有结果
exinclude() 返回不满足条件的所有结果
order_by()  排序order_by('p_age') 按照年龄排序
values()	这个可以对返回的结果包装成一个列表,每一个元素是一个字典({’字段名':value})适合转为json

返回单个的方法

get()
first()
last()
count()		统计个数
exisits()	返回布尔值

这些所有的方法都是可以连用的

查询示例

def get_age(request):
	person = Person.objects.all().first()
	print(person.name)

这个是一个简单的查询,后面还可以接很多的过滤…
例如我要查询年龄在大于18小于80的我们可以这样写

persons = Person.objects.filter(p_age>18).filter(p_age<80)

也可以这样写.

persons = Person.objects.filter(p_age__gt=18).filter(p_age__lt=80)

变量名__条件 = 值
这样的形式来
那么条件大概有
gt >
lt <
gte >=
lte <=
exact =
in 在什么中:Person.objects.filter(p_age__in=[18,20,30])

contains : 包含类似于sql中的like like %xx%(icontains忽略大小写)
startswith :以什么开头(istartswith)
endswith :什么结尾(iendswith)

现在我查询名字当中有"X"的

persons = Person.objects.filter(p_name__contains="X")
for person in persons:
	print(person.p_name)
	

那么现在我们通过这个来简单的去实现一下我们的人事验证,我们假设名字是用户名,年龄是密码,看看这个人是不是这个人.

def find_person(person_name,person_age):
	persons = Person.objects.filter(p_name=person_name)
	if person.exists():#person.count()
		person = persons.first()
		if person.p_age == person_age:
			print("信息无误")
		else:
			print("年龄错误")
	else:
		print("查无此人")
		
	
	

查询切片

还是先前的例子.

persons = Person.objects.filter(p_age>18).filter(p_age<80)

这个家伙返回的是一个可迭代对象,那么就意味着可以进行切片.
但是这个切片的原理其实是类似于sql当中的limit offerset操作的.并不是直接把全部结果加载到内存当中,然后进行切片操作的.

persons = Person.objects.filter(p_age>18).filter(p_age<80)[0:3]
左闭右开
[0,3)

此外就是切片当中不能有复数原因就是那玩意是limit操作

跨关系查询

这个其实说白了就是表的关联.
现在假设创建两个表,一个是学生表,一个是班级表,关系为多对一。

class Grade(models.Model):
	g_name = models.CharField(max_length=32)
	

class Student(models.Model):
	s_name = models.CharField(max_length=16)
	s_grade = models.ForeignKey(Grade) #添加外键约束
	

这里的话其实有两个方法,假设我们查询有个叫 小明 的学生的班级是什么.
第一个分开来一步步查询.我们先假设名字是唯一的

student = Student.objects.get(s_name="小明")
grade_name = student.s_grade.g_name

一次性查询,一步到位,我们直接查班级

grade_name = Grade.objects.filter(student__s_name="小明").first().g_name

F 对象

这个其实是和查询过滤有关的,在Django.db.models下,这个主要是可以帮助我们对两个字段进行比较.
例如:

class Company(models.Model):
	c_name = xxxxx
	c_girl = xxxxx 男孩人数
	c_boy = xxxxxx 女孩人数

现在我要把男孩比女孩多的公司找出来

companies = Company.objects.filter(c_boy>F('c_girl'))
或者
companies = Company.objects.filter(c_boy__gt=F('c_girl'))

Q对象

这个主要是帮助我们多个条件过滤用的.好处就是不用写那么多过滤方法了.
例如:

persons = Person.objects.filter(p_age>18).filter(p_age<80)

可以改成这样

persons = Person.objects.filter(Q(p_age>18) and Q(p_age<80))
此外还可以这样
persons = Person.objects.filter(Q(p_age>18) & Q(p_age<80))

or  ---> |
not ---> ~

聚合函数

举个例子找我们先前定义的Person我们找年纪最大的怎么找

max_person = Person.objects.aggregate(Max("p_age"))
Max也在 django.db.models下
此外还有:
	Max
	Avg
	Min
	Sum
	Count
	返回结果如下格式:
	例如:{'c_age_max':88}

这个其实是做了封装.

模型成员

在前面不知道你注意到了没有,每次我要查询数据都需要调用objects那么这玩意到底为何物嘞.这个其实就是一个模型.

但是这里分为两种,一种是隐性的一种是显性的.我们的objects就是隐性的,最明显的原因就是,我们压根就没有定义这玩意.这个是我们父类Model自带的.那么显性又是怎么样子的呢,显然我们自己定义的就是显性的.那么这样做的好处是什么呢,那就是我们可以自己制定一个规则.
下面举个简单的例子.

显性模型

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	is_delete = models.BooleanField(default=False)#0没有1已删除

假设我们要拿到数据拿到的数据必然是没有删除的.那么常规下我们可以这样写

persons = Person.objects.filter(is_delete=False)

但是显然我们每次拿数据的时候都需要过滤一下,这个那么如果每次都这样写的话就会显得很麻烦,所以我们可以这样自己指定一下模型,写个过滤规则.

class PersonManager(model.Manager):
	def get_queryset(self):#这个是模型返回的数据的方法
		return super(PersonManager,self).get_queryset().filter(is_delete=False)

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	is_delete = models.BooleanField(default=False)#0没有1已删除
	objects = PersonManager()#你叫其他名字也可以到时候这样例如:p_m,那么调用就是:Person.p_m.all()等
	
	

下图是Model.Manger的部分代码

软删除

都说到这里了,就不得不说一下软删除这玩意,一个数据尤其是重要数据例如用户数据是不可能说删除就删除的,那么这个时候的删除并不会在数据库中真正删除,而是可以通过我们刚刚那个类似于is_delete的字段的值来进行适当的隐藏,过滤.也就是说在删除的时候我们只是设置那个值为真,并且我们自己指定了模型所以为真的就会先被过滤,那么一来数据就实现了一种删除效果.
怎么做呢,也很简单,重写delete方法即可.

class Person(models.Mode):
	p_name = models.CharField(max_length=16,unqiue=True,null=False)
	is_delete = models.BooleanField(default=False)#0没有1已删除
	objects = PersonManager()#你叫其他名字也可以到时候这样例如:p_m,那么调用就是:Person.p_m.all()等
	def delete(self):
		self.is_delete = True
		self.save()	

这样一来就好了.

补充(Django数据库时区域问题)

由于在Django当中自己使用了一个时区(我们自己设置的,默认也是世界时间)
这个三个解决方案,一个是设置数据库的时区.
还有一个就是将错就错暂时不去生效时区设置

最后一个是校验时区,把我们当前的时区改为世界时区.
参考博客:django—时区问题(USE_TZ)

以上是关于Django学习系列(二,Models数据操作篇)的主要内容,如果未能解决你的问题,请参考以下文章

Django学习第6篇:Django之ORM单表操作(增删改查)

Django学习第5篇:Django之ORM数据库操作注意细节

Django学习系列之ORM-QuerySetAPI

Django models ORM基础操作--白话聊Django系列

MybatisPlus实现基本CURD&逻辑删除&代码生成(对标Django系列学习二)

04-Django-基础篇-模型