39.django的ORM模型

django的orm(模型model)

创建的模型(model)的步骤:

​ 1.需要创建一个数据库

​ 2.在settings中配置连接数据库的信息:

​ 3.在对应的app中的__init__文件下面:
​ import pymysql
​ pymysql.install_as_MySQLdb()

​ 4.还需要在settings里的INSTALL_APPS中将对应app添加进去

表中数据列类型

django中数据类型

mysql orm
tinyint 不存在
smallint SmallIntegerField
mediumint 不存在
数字 int (unsigned) IntegerField(PositiveIntegerField)
bigint BigIntegerField (PositiveBigIntegerField)
decimal DecimalField
float FloatField
double 不存在
char 不存在
字符串 varchar CharField
text TextField
时间日期 date DateField
datetime DateTimeField

django中参数

参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引

对django admin 定义了一些特殊的数据类型:比如EmailField,URLField,FilePathField,FileField等等

orm基本的增删改查

1.创建表

一个类对应一个表,比如新键一个用户类,可以使用继承django中的models.Model来新键

对应字段设置为对象,比如id可以通过models.AutoField设置为自增整形类型,name可以通过models.CharFeild设置为varchar类型。

再将类转化为实际的表,通过2个命令

python manage.py  makemigrations  ### 生成迁移文件
python manage.py  migrate   ### 生成实际的表

2.增删改查

单表:

查询

models.UserInfo.objects.all() 
#<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
models.UserInfo.objects.values("name", 'age')
#<QuerySet [{'name': 'wdr', 'age': '18'}, {'name': 'sima', 'age': '16'}]>
models.UserInfo.objects.values_list('name','age')
#<QuerySet [('wdr', '18'), ('sima', '16')]>
models.UserInfo.objects.first()
#查询到的第一个对象UserInfo: UserInfo object
models.UserInfo.objects.filter(id=1).first()
#用filter加条件进行筛选查询,若想要查询id>3的可以通过id__gt=3来设置便可,如果不加条件相当于all()

增加

models.UserInfo.objects.create(name='wjk',age='19',ut_id=1)
#或者用可变长形参形式将字典打散为关键字传入方式写入
添加多条数据
info = [
    models.UserInfo(name='root1', age=34, ut_id=1),
    models.UserInfo(name='root2', age=35, ut_id=2),
    models.UserInfo(name='root3', age=36, ut_id=1),
    models.UserInfo(name='root4', age=37, ut_id=3),
    models.UserInfo(name='root5', age=32, ut_id=1),
]
 models.UserInfo.objects.bulk_create(info)

删除

models.UserInfo.objects.filter(id=4).delete()

更新

models.UserInfo.objects.filter(id=3).update(name='yyqx')

一对多连表的操作:

正向查询

res=models.UserInfo.objects.all()
for obj in res:
    print(obj.name,obj.age,obj.ut.title)
#### 神奇双下划线
models.UserInfo.objects.values('name', 'age', 'ut__title')

models.UserInfo.objects.values_list('username', 'age', 'ut__title')

反向查询

res = models.UserType.objects.first()
obj = res.userinfo_set.first()

# 通过表名小写_set反向查询这个表内信息
用表名小写__字段名
models.UserType.objects.values("title", 'userinfo__id', 'userinfo__age', 'userinfo__name')

一对一表的查询

创建一对一表时,通过oneTooneField来设置外键字段: 表示一对一, 默认要求该字段必须是唯一的 unique 外键关系

在正向查询方式和之前一样,反向查询时,由于是一对一的设置,所以在子表中拿到的对象直接点主表名的小写就可以拿到主表对象直接点要查询的字段即可。

多对多表的查询

第一种方式:手动创建第三张表

创建一个中间表,设置两个外键分别指向需关联的两个表,在ORM设置时,还需通过Meta类将两个外键设置为联合唯一的约束,通过在Meta类中使用unique_together来设置。

在跨表查询时,可以通过其中一个主表反向查询到中间表再跨到另一个主表中查询信息。

也可以直接通过中间表正向查询两个主表内的信息

第二种方式:manytomanyfiled设置外键

通过在某一个表中设置manytomanyfiled关联到另一个表,这样django就会在数据库中自动创建一个中间表,分别设置了外键指向这两个表,并且还提供了add()方法进行添加,remove()方法进行删除,clear()方法进行清空

区别:
第一种方式比较的灵活, 自己可以添加任意的字段
而第二种方式比较的死板, 只能生成两个字段,
如果将来业务扩展的时候, 就需要重新打破重来

ORM高级查询

### 1. 字段名过滤
res=models.UserInfo.objects.filter(id=1,age=18).values() 
# filter相当于sql中的where,可以通过逗号将要筛选的字段名隔开,然后表示并列and查询

####2. in not in
res=models.UserInfo.objects.filter(id__in=[1,2]).values()
# in通过在filter函数字段名__in=[]来筛选
res=models.UserInfo.objects.exclude(id__in=[1,2]).values()
# not in通过在exclude函数字段名__in=[]来筛选

####3. between...and
res=models.UserInfo.objects.filter(id__range=[1,3]).values()

####4. like模糊查询
# 字段名__startswith,endswith,contains表示包含,regex后可跟正则表达式
res=models.UserInfo.objects.filter(name__startswith='s').values()
res=models.UserInfo.objects.filter(age__endswith='8').values()
res=models.UserInfo.objects.filter(name__contains='yq').values()
res=models.UserInfo.objects.filter(name__regex='^y').values()

### 5.count计数
res=models.UserInfo.objects.filter(id__range=[1,3]).count()

### 6.order by
res=models.UserInfo.objects.values().order_by('age')
res=models.UserInfo.objects.values().order_by('-age')

#### 7. group by
from django.db.models import Count, Min, Max, Sum
res = models.UserInfo.objects.values("name").annotate(sum_age=Sum('age'))

#### 8. limit
# 切片
res = models.UserInfo.objects.values()[1:3]

##### 9. last
res = models.UserInfo.objects.last()

##### 10. only 表示只取某一列
res=models.UserInfo.objects.all().only('name')

#### 11. defer 排除某一列取其它的
# res=models.UserInfo.objects.defer('name').values()

#### 12. or
##### Q
from django.db.models import Q
res = models.UserInfo.objects.filter( Q(age='18') | Q(name='wdr') )

#### 13.F
# 如果有需求对某一行进行整体操作,可通过导入F函数进行循环操作,比如对某一行加一个数,通过update更新时可将要改的字段放在F方法中加上某个数赋给一个新的字段名循环更新即可。
from django.db.models import F
models.UserInfo.objects.update(name=F('name')+1)

#### 14.distinct
# models.UserInfo.objects.values("name", 'age').distinct('name')

print(res)

#### 15.原生sql 类似pymysql
# from django.db import connection, connections
# cursor = connection.cursor()  # cursor = connections['default'].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()
# print(row)

QuerySet

  查询集,类似一个列表,包含了满足查询条件的所有项。QuerySet 可以被构造,过滤,切片,做为参数传递,这些行为都不会对数据库进行操作。只有你查询的时候才真正的操作数据库。意味着QuerySet是惰性执行的----即创建查询集不会带来任何的数据库访问,直到查询集需要求值的时候,Django才会真正运行这个查询。

常用QuerySet方法
<1> all():                 查询所有结果
 
<2> filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 
<3> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 
<4> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
 
<5> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
 
<6> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<7> order_by(*field):      对查询结果排序
 
<8> reverse():             对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
 
<9> distinct():            从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
 
<10> count():              返回数据库中匹配查询(QuerySet)的对象数量。
 
<11> first():              返回第一条记录
 
<12> last():               返回最后一条记录
 
<13> exists():             如果QuerySet包含数据,就返回True,否则返回False


django自带分页处理

from django.core.paginator import Paginator
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    paginator = Paginator(userlist, 10)

    # has_next              是否有下一页
    # next_page_number      下一页页码
    # has_previous          是否有上一页
    # previous_page_number  上一页页码
    # object_list           分页之后的数据对象的列表
    # number                当前页
    # paginator             paginator对象
    users = paginator.page(cur_page)
	return render(request, 'index.html', {"users": 		users})