刨析django---模型类

ORM 映射

在这里插入图片描述
类映射为表
类属性映射为表字段
类的对象实例映射为一行记录

优点

  1. 避免写SQL语句,使用面向对象的方式来操作数据库,使用比较方便。
  2. 实现项目与数据库解耦,切换数据库只需简单配置。

缺点

  1. 针对复杂的业务,操作比较繁琐
  2. 性能没有SQL效率高

 

Django配置数据库

在配置文件settings.py中

DATABASES = {
	"default":{
		"ENGINE":"django.db.backends.mysql",
		"HOST":"localhost",
		"PORT":"3306",
		"USER":"lauf",
		"PASSWORD":"lauf123",
		"NAME":"my_db",
		"CHARSET":"utf8",
	
	}

}

注意
django连接mysql使用python的mysqlclient库,需要安装:sudo pip3 install mysqlclient
若报错mysql_config,则需在linux系统环境中安装如下依赖:

sudo apt-get install libmysqlclient-dev
sudo apt-get install default-libmysqlclient-dev
sudo apt-get install python3-dev

#查看是否安装成功
sudo apt list --installed | grep -E "libmysqlclient-dev|python3-dev"

查看pip3是否安装成功

pip3 freeze | grep -i "mysqlclient" 

另外也可以使用pymysql代替mysqlclient,操作方式为在settings.py 中配置:

import pymysql
pymysql.install_as_MySQLdb()

 

创建模型类

  • 创建user应用;
    • python manager.py startapp user
  • 在user应用中,展示创建User模型类
#在项目目录下,创建user应用, linux环境中需要使用python3;windows下仅仅python
python3 manage.py startapp user

# 安装应用 settings.py
INSTALLED_APPS = [
	...,
	"user",
]

#为应用定义模型类 user>models.py
from django.db import models

# 表结构 user_t
# username  varchar(50)
# password  char(64) not null
# score decimal(4, 2)
# is_delete  bool default false
# created_time  datetime
# udpated_time  datetime
class User(models.Model):
	username = models.CharField("姓名",max_length=50,primary_key=True)#必须给max_length
	password = models.CharField("密码",max_length=50,null=False)
	score = models.DecimalField("分数",max_digits=4,decimal_places=2) #小数点位置
	is_delete = models.BooleanField("是否删除",default=False)
	created_time = models.DateTimeField("注册时间",auto_now_add=True)
	updated_time = models.DateTimeField("更新时间",auto_now=True)
	def __str__(self):
		"""打印对象时,显示的信息"""
		return self.username # 必须返回字符串
		
	class Meta:
		db_table = "user_table" #更改表名字
		managed = True
		# app_label = "default"  # 控制使用的数据库,需要结合database_router.py一起使用,否则无法生成迁移文件、无法迁移

# 迁移模型类,到数据库中
python3 manage.py makemigrations
python3 manage.py migrate

在没有指定主键时,Django自动创建一个id作为主键。

 
练习为user表添加一个hobby字段

#在模型类中,增加类属性
hobby = models.CharField("爱好",max_length=50,default="") #防止之前的数据没有这个字段而报错,必须给一个default

#重新生成迁移文件, 迁移到数据库 

 

模型类的字段类型

  1. BooleanField()
    对应数据库中的tinyint,0/1; Django中为True/False
  2. CharField()
    对应数据库中的varchar,必须指定max_length
  3. DateField()
    对应数据库中的date,
    参数,auto_now = True, 更新时间
    auto_now_add = True,第一次插入时间
    default 给一个默认值
  4. DateTimeField() 使用同DateField()
  5. FloatField() 对应数据库中的double
  6. DecimalField() 精确的小数,对应数据库decimal
    必需参数:max_digits=5总位数,decimal_places=2 小数点位置
  7. EmailField() 对应数据库varchar
  8. IntegerField() -->int
  9. ImageField() —>varchar(100) 存储路径
  10. TextField —>longtext 长文本

类属性的约束

primary_key, bool, 是否为主键
blank,bool,是否为空,admin后台管理的时候可以不写内容的字段
null,bool,该列是否可为null空值
default,默认值
db_index,bool,是否在该列设置索引
unique,bool, 该列的值是否唯一,唯一索引
db_column列的名称,默认使用类属性作为列名
verbose_name, 后台显示的字段名字

 

练习

创建一个Book模型类,类属性如下:
title, 书名,字符类型,最大长度50,且值唯一
price, 价格,精确小数,最大5位数,一位小数
publish,出版社,字符类型,最大长度50,不能为 null
打印对象时,输出书名,且修改表名为book_table
每次修改模型类,都要迁移;迁移失败,则删除migrations下的迁移文件,除了__init.__py,删除库,重建库,重新迁移
 

模型类的CRUD

增加数据

#使用模型类的对象管理器objects.create
User.objects.create(username=xxx,password=xxx,email=xxx,phone=xxx)

#或者
user = User(username=xxx,password=xxx,email=xxx,phone=xxx)
user.save()

可以在Django shell中尝试,代码更改后需重新进入

python3 manage.py shell
>>from user.models import User

查询

User.objects.all() #查询所有数据-->QuerySet对象,遍历获取每个数据对象

#按照字段取值,返回的QuerySet为字典列表
User.objects.values('col1',"col2",...)
#返回的QuerySet为元组列表
User.objects.values_list("col1","col2")

#排序
User.objects.order_by("-age") #降序,默认升序
User.objects.values("username",'age').order_by("age",'-xx') #按照age升序

QuerySet对象.query  #拿到sql语句

练习,
配置一个路由/user/all,
请求方式GET,
视图,show_all

#views.py
def show_all(request):
	users = User.objects.all()
	return render(request,"index.html",locals())
#locals()函数局部变量的字典

让前端以表格形式显示所有的用户数据

条件查询

User.objects.filter(username="jack",age=12) #多个条件and 连接,返回QuerySet对象

#排除查询
User.objects.exclude(username="jack")#排除该条件的数据,返回QuerySet

#获取一个对象,返回对象
User.objects.get(username="jack") 
#查询到多个对象,报错
#没有数据也报错,注意异常捕获

#查询谓词
字段__谓词
User.objects.filter(id__exact=1) #id为1
User.objects.filter(id__gt=1) #id>1
User.objects.filter(id__lte=5) #id<=5
User.objects.filter(username__exact="jack") #username 为jack
User.objects.filter(username__contains="jack")#username中包含jack
User.objects.filter(username__startswith="j") #以j开头的
User.objects.filter(username__endswith="k")
User.objects.filter(username__in=["jack","tom"])#是否在范围内
User.objects.filter(age__range=(25,35))

更新

#更新一个对象
obj = User.objects.get(username="jack")
obj.age = 30
obj.save()

#批量更新
queryset = User.objects.filter(age__gt=5)
queryset.update(age=20)

在以表格形式显示用户信息的基础上,完成用户信息的更新,删除两个按钮的功能。
<a href=“book/update/{{ obj.id }}”>更新
<a href=“book/delete/{{ obj.id }}”>删除

input输入组件:
不可编辑,disabled=“disabled”
不提交,不设置name属性

删除

#删除单个对象
obj = User.objects.get(username="jack")
obj.delete()

#批量删除
queryset = User.objects.filter(age__lt=5)
queryset.delete()

#伪删除,不真正删除数据
is_delete = models.BooleanField("是否删除",default=False)
#查询数据时,只查询is_delete为False的数据

 

聚合查询与原生sql

F对象和Q对象

F对象,表示一行记录的某个字段的信息,而不获取数据。

from django.db import models
#在高并发处理中,防止操作错误
user = User.objects.get(username="jack")
user.age = models.F("age") + 1 #原来的值加1

#同一行数据的字段之间的比较
user = User.objects.filter(age__gt=models.F("oage"))

Q对象,包裹查询条件

Q(age__gt=5)&Q(age__lt=10) #且
Q(age__gt=5)|Q(username__exact="jack") #或
~Q(age__exact=5) #非

#查询姓名为‘jack’或者年龄不为20的用户
from django.db import models
queryset = User.objects.filter(models.Q(username="jack")|~models.Q(age__exact=20))

聚合

对查询结果,进行统计分析

from django.db.models import Sum,Avg,Min,Max,Count
#整表聚合
d = User.objects.aggregate(f=Count("id"))
#{"f":100}
#queryset聚合
User.objects.filter(username__contains="jack").aggregate(r=Count(id))

#分组聚合
#先拿到一列的值
c = User.objects.values("addr",...)
#分组,聚合
c.annotate(r=Count("id"))
#<QuerySet [{"addr":"China","r":5},{"addr":"B","r":8}]>

#例子
User.objects.values("email").annotate(r=Count("username"))
Out[35]: <QuerySet [{'email': 'test email', 'r': 1}, {'email': '1000000', 'r': 1}, {'email': 'g1', 'r': 1}, {'email': 'g2', 'r': 3}, {'email': 'g3', 'r': 1}, {'email': '944582529@qq.com', 'r': 1}, {'email': '123', 'r': 1}, {'email': '123456', 'r': 1}]>

原生是sql

User.objects.raw(sql,[ parameter,])
返回RawQuerySet,只能查询,遍历取数据,不能做其他操作
不建议使用

User.objects.raw("select * from user_table where id=%s"%("5 or true"))
#以上查询出所有的数据,自己拼接的方式
#select * from user_table where id=5 or true;

#参数化的方式,防止sql注入
User.objects.raw("select * from user_table where id=%s",["5 or true"])
#django 拼接的结果 select * from user_table where id='5 or true'
#查询时,只取第一个5转为整数

#游标方式
from django.db import connection
with connection.cursor() as cur:
	cur.execute(sql,[]) #写入
	cur.execute("insert into user_table(username,password,email,phone,is_delete,created_time,updatd_time) values(%s,%s,%s,%s,%s,%s,%s)",["lucy","123","qq","234567",False,"2019/11/9","2019/11/9"])

#原生sql插入数据时,自己处理所有的字段

问题总结

  1. 使用ORM操作数据库时,尽量避免手动操作库表
  2. 模型类的级联删除、default默认值等,只有通过模型类操作db时才生效。
  3. 数据库中的表一旦生成,就不能手动删除。
  4. 局部迁移
python manage.py makemigrations app1
python manage.py migrate app1
  1. 继承的BaseModel需第一次就设计好,并迁移成功。
  2. User.objects.update_or_create()
# 更新 或者 创建
# 根据user字段查询,有则使用defaults更新;否则创建
User.objects.update_or_create(defaults={"token": token}, user=user)

迁移问题

  1. no migration to apply
    删除django_migration表中的迁移记录;重新迁移

 
 
 
 
下一篇:Django 后台管理

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值