Django model层开发

模型01

一、MTV概述

1. Model - 模型 :模型是数据的唯一可靠的来源,实际上是要与数据库交互。

2. Template - 模板: 使用HTML来给用户展示界面

3. Views - 视图(函数): 负责接收请求处理业务逻辑,视图也是数据库和模板的中间人。

二、ORM机制

ORM:
	Object Relational Mapping - 对象关系映射(面向对象和关系性数据库之间的一种映射关系)
核心:
	采用面向对象的方式与数据库进行交互

对比:

未使用ORM之前:
	import MySQLdb
	conn = MySQLdb.connect(xxx)
	...
	cursor.execute(insert / select )  #使用原生的SQL语句  
	...
	conn.close()

使用ORM之后:
	类和对象
	class User(models.Model):
		username = xxx
		password = xxx
	在ORM中,这样的一个类,对应的是数据库中的一张表
    存储数据: user = User(username,password)  user.save()  # 将数据存储到数据库表中

优势(了解):

1. 使用面向对象的方式更符合程序员的思维方式  
2. 使用ORM的方式操作数据库,更加简单和方便
3. 使用ORM程序员无需关心程序底层使用的是MySQL、Oracle、SQLite等,更换数据库时,ORM会自动进行转换

三、Model层的开发过程

基本开发流程

1.  安装数据库驱动
		pip install mysqlclient 
		
2. 配置数据库settings.py
            DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',  # 修改为mysql
                'NAME': 'modeldb',                     # 库名
                'HOST': '127.0.0.1',	               # 主机名 ip
                'PORT': 3306,						 # 端口号
                'USER': 'root',	                       # 用户名
                'PASSWORD':'123456'                    # 密码
              }
        	}
		# 如果出现版本不兼容  则添加以下配置
		from django.db.backends.mysql.base import DatabaseWrapper
		DatabaseWrapper.data_types['DateTimeField'] = "DateTime"
	
3. 创建一个app,并挂载app
		python manage.py startpp modelapp
		在settings.py文件的 INSTALLED_APPS = [xxx,'modelapp']
	
4. 打开models.py 定义model类 
	    # 这里定义的model将来会对应库中的一张表
		class User(models.Model):
			username = models.CharField(max_length=20)
			password = models.CharField(max_length=20)
			
5. 执行迁移操作
		# 在terminal中执行以下指令:
	    python manage.py makemigrations    # 生成一个记录文件  此时模型并没有生成到数据库
	    python manage.py migrate           # 会根据model类生成一张表	    数据库已经有了对应的表

测试model

# 总结:
	ORM对象关系映射:
		1. 一个model类对应数据库中的一张表
		2. 类中的属性对应表中的字段
		3. 一个model类的对象对应的是表中的一行数据
要操作一行数据,就是操作一个model对象,要操作一个字段就是操作对象的属性,要操作表就是操作	

四、模型字段

官网字段详解

1、字段类型
字段类型描述
AutoField一般不直接使用,默认为主键的类型,不需要自己定义
SmallIntegerField数据库中的:smallint 2字节
IntegerField数据库中的:int 4字节 -2147483648~2147483647
BigIntegerField数据库中的:bigint 8字节
FloatField数据库中的:double
Decimal(max_digits=5,decimal_places=2)数据库中的:decimal(5,2)
CharField(max_length=20)数据库中的:varchar(20)
TextField数据库中的:longText 长文本
BooleanField (值:True / False)数据库中的:tinyint (1和0)
NullBooleanField(值:True / False / None)数据库中的:tinyint (1 / 0 / null)
DateField数据库中的:date
TimeField数据库中的:time
DateTimeField数据库中的:datetime
可选参数:auto_now=True 表示更新时间或auto_now_add=True第一次添加时间
ForeignKey外键字段 一对多
OneToOneField一对一
ManyToManyField多对多
2、字段参数
1. null 默认为False 不能为空
		name = models.CharField(max_length=20,null=False) 字段默认不能为空
		name = models.CharField(max_length=20,null=True) 字段可以为空
		
2. default 定义默认值
		name = models.CharField(max_length=20,default='jingjing') 
	   # 这里定义的默认值并不会作用到数据库表中,仅仅表示将来构造对象时可以不添加该参数
       # e = Employee(age=18,gender=True)  e.save()
       
3. primary_key 定义主键 (不常用)
		id = models.AutoField(primary_key=True) # 一般不自己定义
		
4. unique 唯一
	    name = models.CharField(max_length=20,unique=True) # 名字是唯一的 不能重复
	    
5. db_column 定义字段的别名 (不常用)
		# 定义该字段在数据库中的列名 如果不指定则使用属性  指定则db_column的值为准
		gender = models.BooleanField(db_column='xb')   # 一般不建议修改列名
		
6. db_index 定义索引
		age = models.SmallIntegerFeild(db_index=True) # age列就有了索引
		# select * from employee where age=18;
3、Meta元数据

官网元数据参数列表

# 元数据类:可以指定生成的表名、排序方式、联合约束等
1. db_table = 'xx' 定义表名
2. ordering = ['列名'] 或 ['-列名'] 或 ['列名1','列名2']   定义排序规则
3. unique_together = ('列名1','列名2') 或 ( ('列名1','列名2') , ('列名3','列名4') )

class User(models.Model):
	xxx
	
	class Meta:
		db_table = '表名'

五、增删改操作

这一节,需要使用model类(对象),来对数据库进行增删改操作以下代码可以如下执行:	方式一:将代码写在视图函数中,然后在浏览器中输入URL访问		方式二:打开pycharm左下角的Python Console,然后导入model类 from modelapp.models import User		方式三:		在tests.py文件或自己新建一个.py文件,加入以下代码				import django,os   # 导入django和os包		os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_lession_2005.settings") # 将manage.py文件的第6行复制过来		django.setup()		from modelapp.models import User  # 导入model类				# 这里写测试代码		# 使用右键run 单文件
1、增加数据(创建对象)
# 方式一: 先创建对象再调用save方法user = User(name='Tom', age=18, salary=23451, birthday='2000-1-1')user.save()# 方式二: 直接使用类名.objects.create()即可User.objects.create(name='Jack',age=20,salary=12341,birthday='2002-2-1')
2、删除数据
# 1. 先获取数据 user = User.objects.get(id=1) print(user)# 2. 然后调用delete方法 user.delete()# 删除所有行users = User.objects.all()users.delete()
3、修改数据
# 1. 获取数据user = User.objects.get(id=4)# 2. 修改数据 - 实际就是操作对象的属性user.age = 50# 3. 调用save保存到数据库 -- 切记一定要保存user.save()

六、查询操作

官方查询API

1、QuerySet类
1. 每一个model类,都有一个objects属性(类名.objects),该属性的类型为manager类型		t = User.objects 		print(type(t))  # 类型为Manager --<class 'django.db.models.manager.Manager'>	2. 对对象的检索(查询),都通过Manager来构造一个QuerySet对象来实现的		user = User.objects.get(id=1)		上述代码中,看到的是Manager调用它的get方法实现了查询,但实际情况是Manager构造了一个QuerySet对象来实现的查询	3. Manager对象和QuerySet对象的关系:		Manager是一个管理者,它不是真正的执行者 -- 不是真正干活的人		QuerySet是实际执行查询操作的,它才是真正干活的人		4. User.objects.all() 		是Manager调用了all()方法,但它的内部并没有直接执行查询操作,而是让QuerySet调用了all()方法执行的查询操作		5. 	all()方法的返回值		QuerySet对象 -- 查询集 它本身是可以执行查询操作也可以存放查询结果	
2、查询方法
如下所有的查询方法都是QuerySet实现的,只不过每个Model类在做查询操作时,都是先交给Manager,然后Manager接收到查询请求后,调用QuerySet对应的方法最终实现查询。所以QuerySet是查询动作的核心支撑.Manager的任务是管理QuerySet,在有需要的时候去调用QuerySet.
2.1 基本查询方法
1. all()方法		用法: User.objects.all()		作用: 查询全部数据		返回值:QuerySet对象 - 类似于一个列表,每一个元素是Model对象 <QuerySet [<User: User object (1)>, <User: User object (2)> ...]		2. get()方法		用法:User.objects.get(属性名=值)		作用:只能查询一条数据(不能多不能少)		返回值:Model对象		eg: User.objects.get(id=1)  User.objects.get(pk=1) User.objects.get(age=18)	# 注意:get查询不到结果或结果多于1条则报错    # 查询不到结果:User matching query does not exist.    # 查询多于1条:get() returned more than one User -- it returned 2!    3. filter()方法		用法:User.objects.filter(属性名=值)		作用:可以查询空或1条或多条数据 (介于get和all)		返回值:Query对象 - 如果没有查询到数据返回为空的QuerySet		eg: User.objects.filter(age=18)  		4. count()方法		用法:User.objects.count()		作用:查询结果的数量		返回值:int类型		eg: User.objects.count()  / User.objects.filter(age=18).count()		5. first()方法和last()方法:		用法:User.objects.first() / User.objects.last()		作用:获取结果中的第一条 或 最后一条数据		返回值: model对象6. exclude()方法:		用法:User.objects.exclude(属性名=值)		作用:查询相反的结果 -- 排除		返回值:QuerySet对象		eg: User.objects.exclude(age=18) 查询年龄不是18的数据
2.2 排序方法
# 默认按升序排列users = User.objects.order_by('age')print(users)# 降序排列users = User.objects.order_by('-age')print(users)# 先按年龄排序,年龄相同时按姓名排序users = User.objects.order_by('age','name')print(users)

补:限制操作

# 取结果集中的一部分数据users = User.objects.all()print(users[0])print(users[1:])# print(users[:-2])# print(users[-1])# 注意:QuerySet的用法和列表类似,但不支持负数下标# 如果的确想使用负数下标,可以先将QuerySet对象转为列表list(users)[-1]
2.3 条件查询
1. 在众多的查询方法中,适合做条件查询的有 get(id=1)、filter(age=18)、exclude(age=20)但是这些查询方法只能做等值查询2. 如果想做比较运算 < > <= >= ,则需要修改上述方法中的参数  filter(id>1)--错误   解决:将上述的四个符号替换为【lt gt lte gte】  users = User.objects.filter(id__gt=1)  # 查询id>1print(users)users = User.objects.filter(age__gte=18) # 查询年龄大于等于18print(users)
2.4 模糊查询
# select * from t_user where name like '%z%';1. contains / icontains   包含 / 包含(对大小写不敏感)2. startswith / istartswith 以..开头3. endswith  / iendswith 以..结尾eg:	User.objects.filter(name__contains='a')  # 查询名字包含a的用户
2.5 范围查询
# between .. and   /  in # select * from t_user where id in(1,3,5);1.  in      在某个集合中 `id__in=(1,3,5)`2.  range   在某个范围里 `id__range=(2,5)`eg:	User.objects.filter(id__in=(1,3,5))	User.objects.filter(id__range=(2,5))  # 闭区间
2.6 空值查询
# 查询没有记录生日的用户users = User.objects.filter(birthday=None)print(users)# 查询没有记录生日的用户users = User.objects.filter(birthday__isnull=True)print(users)# select * from t_user where birthday is null / is not null# 查询记录了生日的用户users = User.objects.filter(birthday__isnull=False)  # select * from t_user where birthday is null / is not nullprint(users)
2.7 日期查询 - 了解
  • year / month 1-12 / day / hour / minute / second / week 一年第几周 / week_day 星期
# 需求:查询生日为2019年的用户users = User.objects.filter(birthday__year=2019)print(users)
2.8 映射查询(查询部分列)
# select * from t_user;   - 查询所有列# select name,age from t_user; - 查询部分列User.objects.all() # 查询所有行及所有列User.objects.get(id=1) # id为1的这一行的所有列
  • values(列名1,列名2…) # 返回值为QuerySet对象 元素为字典
users = User.objects.all()print(users) # 所有行所有列 返回值为QuerySet对象,但元素是Model对象# 查询全部列  返回值为QuerySet对象,但元素为字典dictusers = User.objects.values()print(users)# 只查询name和age列users = User.objects.values('name','age')print(users)print(users[0]['name'])
  • only(列名1,列名2…) # 返回值为QuerySet对象 率先查询部分列
# 率先查询name和age 而其它的列需要的时候才会去查询 不需要则不查询  懒加载users = User.objects.only('name','age')print(users)print(users[0].name)print(users[0].age)print(users[0].salary)
2.9 聚合函数
# Max()  /  Min()  /  Sum()  /  Avg()  /  Count()from django.db.models import Max,Min,Sum,Avg,Countusers = User.objects.aggregate(Max('age'),Min('age'),Count('id'))print(users) # {'age__max': 25, 'age__min': 17, 'id__count': 5} users = User.objects.aggregate(x=Max('age'),n=Min('age'),c=Count('id'))print(users) # {'x': 25, 'n': 17, 'c': 5}
2.10 分组统计
语法:	User.objects.values('age').annotate(Max('salary'))	# 以年龄分组,查询每个年龄段的最高薪水
# 示例:emp = Employee.objects.filter(age__gte=1).values('age').annotate(Max('salary')).order_by('age')print(emp)print(result)  # 以年龄分组,查询每个年龄段的最高薪水# 加Where条件# SQL: select max(salary),age from user where age>=18 group by age; result = User.objects.filter(age__gte=18).values('age').annotate(Max('salary')).order_by('age')print(result)# 加Having条件#查询年龄大于1的平均薪水大于5000的每个年龄段的平均薪水# SQL: select avg(salary),age from t_user where age >=18 group by age having avg(salary) >  15000;result = Employee.objects.filter(age__gte=1).values('age').annotate(ag=Avg('salary')).filter(ag__gte=5000).order_by('age')print(result)
2.11 F()和Q()函数
  • F()函数:
User.objects.filter(id__gt=1) # id大于1的用户需求:查询id大于年龄的用户?   User.objects.filter(id__gt=age)  -- 错误解决:	User.objects.filter(id__gt=F('age'))# 什么情况下需要使用F函数:	当查询条件中需要使用到另外的列(属性)时# eg:    # blog   create_time    edit_time	# 查询 被修改过的博客	#  Blog.objects.filter(edit_time__gt=F('create_time'))	
  • Q()函数:
User.objects.filter(id__gt=2,age__gt=18) # 查询id大于2`且`年龄大于18的用户# 需求:查询id大于2 `或` 年龄大于18的用户解决:使用Q()函数  -- 表示或的关系# eg:	users = User.objects.filter(Q(id__gt=2)|Q(age__gt=18))	print(users)		# 表示非  ~   波浪线	users = User.objects.filter(Q(id__gt=2)|~Q(age__gt=18))	print(users)

七、Raw-SQL

Raw-SQL: 原生SQL# 如果上述的查询并不能满足业务需求时,可以使用raw函数users = User.objects.raw('select * from modelapp_user')print(users)print(list(users))for user in users:    print(user)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值