Django ORM(基础)
Django 框架十分强大,自带数据库操作功能。Django 跟 SQLAchemy 一样,也是通过ORM(Object Relational Mapping,关系对象映射)的方式对数据库进行操作,django中遵循 Code Frist (根据代码中定义的类来自动生成数据库表)的原则。
一、创建表
1、在SQLite中创建表
1.1、在app中的models.py中先写类:
from django.db import models
# Create your models here.
class UserInfo(models.Model):
# id列,Django框架会默认生成id(自增,主键),也可以通过AutoField类型自定义主键,不过Django框架默认生成ID列会失效
# 用户名列,字符串类型,最大长度长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
1 AutoField(Field)
2 - int自增列,必须填入参数 primary_key=True
3
4 BigAutoField(AutoField)
5 - bigint自增列,必须填入参数 primary_key=True
6
7 注:当model中如果没有自增列,则自动会创建一个列名为id的列
8 from django.db import models
9
10 class UserInfo(models.Model):
11 # 自动创建一个列名为id的且为自增的整数列
12 username = models.CharField(max_length=32)
13
14 class Group(models.Model):
15 # 自定义自增列
16 nid = models.AutoField(primary_key=True)
17 name = models.CharField(max_length=32)
18
19 SmallIntegerField(IntegerField):
20 - 小整数 -32768 ~ 32767
21
22 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
23 - 正小整数 0 ~ 32767
24 IntegerField(Field)
25 - 整数列(有符号的) -2147483648 ~ 2147483647
26
27 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
28 - 正整数 0 ~ 2147483647
29
30 BigIntegerField(IntegerField):
31 - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
32
33 自定义无符号整数字段
34
35 class UnsignedIntegerField(models.IntegerField):
36 def db_type(self, connection):
37 return 'integer UNSIGNED'
38
39 PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
40 'AutoField': 'integer AUTO_INCREMENT',
41 'BigAutoField': 'bigint AUTO_INCREMENT',
42 'BinaryField': 'longblob',
43 'BooleanField': 'bool',
44 'CharField': 'varchar(%(max_length)s)',
45 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
46 'DateField': 'date',
47 'DateTimeField': 'datetime',
48 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
49 'DurationField': 'bigint',
50 'FileField': 'varchar(%(max_length)s)',
51 'FilePathField': 'varchar(%(max_length)s)',
52 'FloatField': 'double precision',
53 'IntegerField': 'integer',
54 'BigIntegerField': 'bigint',
55 'IPAddressField': 'char(15)',
56 'GenericIPAddressField': 'char(39)',
57 'NullBooleanField': 'bool',
58 'OneToOneField': 'integer',
59 'PositiveIntegerField': 'integer UNSIGNED',
60 'PositiveSmallIntegerField': 'smallint UNSIGNED',
61 'SlugField': 'varchar(%(max_length)s)',
62 'SmallIntegerField': 'smallint',
63 'TextField': 'longtext',
64 'TimeField': 'time',
65 'UUIDField': 'char(32)',
66
67 BooleanField(Field)
68 - 布尔值类型
69
70 NullBooleanField(Field):
71 - 可以为空的布尔值
72
73 CharField(Field)
74 - 字符类型
75 - 必须提供max_length参数, max_length表示字符长度
76
77 TextField(Field)
78 - 文本类型
79
80 EmailField(CharField):
81 - 字符串类型,Django Admin以及ModelForm中提供验证机制
82
83 IPAddressField(Field)
84 - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
85
86 GenericIPAddressField(Field)
87 - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
88 - 参数:
89 protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
90 unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
91
92 URLField(CharField)
93 - 字符串类型,Django Admin以及ModelForm中提供验证 URL
94
95 SlugField(CharField)
96 - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
97
98 CommaSeparatedIntegerField(CharField)
99 - 字符串类型,格式必须为逗号分割的数字
100
101 UUIDField(Field)
102 - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
103
104 FilePathField(Field)
105 - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
106 - 参数:
107 path, 文件夹路径
108 match=None, 正则匹配
109 recursive=False, 递归下面的文件夹
110 allow_files=True, 允许文件
111 allow_folders=False, 允许文件夹
112
113 FileField(Field)
114 - 字符串,路径保存在数据库,文件上传到指定目录
115 - 参数:
116 upload_to = "" 上传文件的保存路径
117 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
118
119 ImageField(FileField)
120 - 字符串,路径保存在数据库,文件上传到指定目录
121 - 参数:
122 upload_to = "" 上传文件的保存路径
123 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
124 width_field=None, 上传图片的高度保存的数据库字段名(字符串)
125 height_field=None 上传图片的宽度保存的数据库字段名(字符串)
126
127 DateTimeField(DateField)
128 - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
129
130 DateField(DateTimeCheckMixin, Field)
131 - 日期格式 YYYY-MM-DD
132
133 TimeField(DateTimeCheckMixin, Field)
134 - 时间格式 HH:MM[:ss[.uuuuuu]]
135
136 DurationField(Field)
137 - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
138
139 FloatField(Field)
140 - 浮点型
141
142 DecimalField(Field)
143 - 10进制小数
144 - 参数:
145 max_digits,小数总长度
146 decimal_places,小数位长度
147
148 BinaryField(Field)
149 - 二进制类型
1 class User(models.Model):
2 name = models.CharField(max_length=32)
3 pwd = models.CharField(max_length=32)
4 #class User(models.Model):
5 # name = models.CharField(max_length=32,db_index=True)
6 # pwd = models.CharField(max_length=32,db_index=True)
7 class Meta:
8 #指定数据库表名:tb1,如果不指定表名将会默认生成表名:app名称 + 下划线 + 类名
9 db_table = "tb1"
10
11 #索引,mysql每一列加上索引就会生成一个文件,因此当上面被注释的User表生成是mysql数据库就会生成一个表,两个文件,
12 #因此不想数据库生成太多索引文件,又想个别列名能够支持索引查询,这个时候就需要用到联合索引,
13 index_together = [ # 联合索引,只会生成一个索引文件 但是有一个缺点就是,遵循最左前缀模式查询
14 ("name", 'pwd'),
15 ]
16
17 # 最左前缀的模式:
18 # select * from where name='xx'
19 # select * from where name='xx' and email = 'xx'
20 # select * from where email = 'xx' # 无法命中索引
21
22 #联合唯一索引,与上面的联合索引一样,就是多了一个列名组合唯一的限制
23 unique_together = (("driver", "restaurant"),)
24
25 #admin中的配置
26 verbose_name = “name” #在admin中会将name显示成names,多加一个“s”
27 verbose_name_plural=““name”” #在admin中会将name显示成name,显示原生自定义的名字
1 null 数据库中字段是否可以为空
2 db_column 数据库中字段的列名
3 db_tablespace
4 default 数据库中字段的默认值
5 primary_key 数据库中字段是否为主键
6 db_index 数据库中字段是否可以建立索引
7 unique 数据库中字段是否可以建立唯一索引
8 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
9 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
10 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
11
12 verbose_name Admin中显示的字段名称
13 blank Admin中是否允许用户输入为空
14 editable Admin中是否可以编辑
15 help_text Admin中该字段的提示信息
16 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
17 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) 想要在HTML中显示choice中的字段值,而不是数学索引,需要用到{{k.get_带choices参数的字段_display}}方法
18
19 error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
20 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
21 如:{'null': "不能为空.", 'invalid': '格式错误'}
22
23 validators 自定义错误验证(列表类型),从而定制想要的验证规则
24 from django.core.validators import RegexValidator
25 from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
26 MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
27 如:
28 test = models.CharField(
29 max_length=32,
30 error_messages={
31 'c1': '优先错信息1',
32 'c2': '优先错信息2',
33 'c3': '优先错信息3',
34 },
35 validators=[
36 RegexValidator(regex='root_\d+', message='错误了', code='c1'),
37 RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
38 EmailValidator(message='又错误了', code='c3'), ]
39 )
1.2、在settings.py中注册app:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app1',
]
1.3、在控制台输出cmd 命令:
python3 manage.py makemigrations #相当于在该app的migrations目录,记录下该app下modes.py所有表结构类型的改动(普通增删改查不记录)
python3 manage.py migrate #将刚刚对于表结构的改动作用至数据库
2、在MySQL中创建表
2.1、在上面步骤1.1 先写类、1.2 注册app的基础上,在与Django project中与project同名目录下的__init__.py文件中配置如下代码:
import pymysql
pymysql.install_as_MySQLdb()
注:# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
2.2,在settings.py中更改数据库配置
#将原先数据库配置注释,使用mysql配置
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test1', # 数据库名称
'USER': 'root', # 用户名
'PASSWORD': '123456', # 密码
'HOST': 'localhost', # ip
'PORT': '3306', # 端口
}
}
2.3、执行命令
python3 manage.py makemigrations
python3 manage.py migrate
注:配置好数据库为mysql后,重新启动Django工程,如果报错mysql django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required;的话, 这是因为 mysql client 端的版本小于1.3.3。最简单的解决办法是:
#找到Django的安装路径的mysql配置下的base.py,如C:\Python36\Lib\site-packages\django\db\backends\mysql\base.py(根据实际安装路径)
#注释这句断言:
#if version < (1, 3, 3):
#raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
二、增删改查
利用Django的ORM连接数据库进行增删改查和其他一些进阶操作。
1、增:
# 第一种方式
models.UserInfo.objects.create(username='root', password='123')
# 第二种方式
dic = {'username': 'root1', 'password': '456'}
models.UserInfo.objects.create(**dic)
#第三种方式
obj = models.UserInfo(username='root2', password='789')
obj.save()
2、删:
models.UserInfo.objects.filter(id="2").delete()
3、改:
models.UserInfo.objects.filter(id=1).update(password="111")
4、查:
models.User.objects.filter(id=1) #id=1
models.User.objects.filter(id=1,name='root') #id=1 and name = root
models.User.objects.filter(id__gt=1) #id>1
models.User.objects.filter(id__lt=1) #id<1
models.User.objects.filter(id__gte=1) #id>=1
models.User.objects.filter(id__lte=1) #id<=1
models.Tb1.objects.filter(id__lt=10, id__gt=1) #1<id<10
dic = {'name': 'xx', 'age__gt': 19} #**字典形式多条件查询
models.User.objects.filter(**dic)
models.Business.objects.all() #QuerySet ,内部元素都是对象 [obj(id,caption,code),obj(id,caption,code),obj(id,caption,code) ]
models.Business.objects.all().values('id','caption') # QuerySet ,内部元素都是字典 [{'id':1,'code': 'QA'},{'id':2,'code': 'PM'},...]
models.Business.objects.all().values_list('id','caption') # QuerySet ,内部元素都是元组 [(1,"QA"),(2,"PM")]
models.Business.objects.get(id=1) # 获取到的一个对象,如果不存在就报错
models.Business.objects.filter(id=1).first() # 获取到的一个对象,如果不存在返回NONE
5、更多进阶操作:
1 # 获取个数
2 #
3 # models.Tb1.objects.filter(name='seven').count()
4
5 # in
6 #
7 # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
8 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
9
10 # isnull
11 # Entry.objects.filter(pub_date__isnull=True)
12
13 # contains
14 #
15 # models.Tb1.objects.filter(name__contains="ven")
16 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
17 # models.Tb1.objects.exclude(name__icontains="ven")
18
19 # range
20 #
21 # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
22
23 # 其他类似
24 #
25 # startswith,istartswith, endswith, iendswith,
26
27 # order by
28 #
29 # models.Tb1.objects.filter(name='seven').order_by('id') # asc
30 # models.Tb1.objects.filter(name='seven').order_by('-id') # desc
31
32 # group by
33 #
34 # from django.db.models import Count, Min, Max, Sum
35 # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
36 # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
37
38 # limit 、offset
39 #
40 # models.Tb1.objects.all()[10:20]
41
42 # regex正则匹配,iregex 不区分大小写
43 #
44 # Entry.objects.get(title__regex=r'^(An?|The) +')
45 # Entry.objects.get(title__iregex=r'^(an?|the) +')
46
47 # date
48 #
49 # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
50 # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
51
52 # year
53 #
54 # Entry.objects.filter(pub_date__year=2005)
55 # Entry.objects.filter(pub_date__year__gte=2005)
56
57 # month
58 #
59 # Entry.objects.filter(pub_date__month=12)
60 # Entry.objects.filter(pub_date__month__gte=6)
61
62 # day
63 #
64 # Entry.objects.filter(pub_date__day=3)
65 # Entry.objects.filter(pub_date__day__gte=3)
66
67 # week_day
68 #
69 # Entry.objects.filter(pub_date__week_day=2)
70 # Entry.objects.filter(pub_date__week_day__gte=2)
71
72 # hour
73 #
74 # Event.objects.filter(timestamp__hour=23)
75 # Event.objects.filter(time__hour=5)
76 # Event.objects.filter(timestamp__hour__gte=12)
77
78 # minute
79 #
80 # Event.objects.filter(timestamp__minute=29)
81 # Event.objects.filter(time__minute=46)
82 # Event.objects.filter(timestamp__minute__gte=29)
83
84 # second
85 #
86 # Event.objects.filter(timestamp__second=31)
87 # Event.objects.filter(time__second=2)
88 # Event.objects.filter(timestamp__second__gte=31)
注:all()、all().values()、all().values_list()示例:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8 <h1>业务线列表(对象)</h1>
9 <ul>
10 {% for row in v1 %}
11 <li>{{ row.id }} - {{ row.caption }} - {{ row.code }}</li>
12 {% endfor %}
13 </ul>
14 <h1>业务线列表(字典)</h1>
15 <ul>
16 {% for row in v2 %}
17 <li>{{ row.id }} - {{ row.code }}</li>
18 {% endfor %}
19 </ul>
20 <h1>业务线列表(元组)</h1>
21 <ul>
22 {% for row in v3 %}
23 <li>{{ row.0 }} - {{ row.1 }}</li>
24 {% endfor %}
25 </ul>
26 </body>
27 </html>
1 from django.shortcuts import render
2 from app1 import models
3
4
5
6 def business(request):
7 v1 = models.Business.objects.all()
8 # QuerySet [obj(id,caption,code),obj(id,caption,code),obj(id,caption,code) ]
9
10 v2 = models.Business.objects.all().values("id", "code")
11 # QuerySet [{'id':1,'code': 'QA'},{'id':2,'code': 'PM'},...]
12
13 v3 = models.Business.objects.all().values_list('id', 'code')
14 # QuerySet [(1,"QA"),(2,"PM")]
15 return render(request, 'business.html', {'v1': v1, 'v2': v2, 'v3': v3})
三、ORM基础操作示例:
简单模拟用户登陆跳转后台,实现编辑用户、新增用户、删除用户、查看用户详情等功能小示例
1、templates:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 </head>
7 <body>
8 <form action="/app2/login/" method="POST" enctype="multipart/form-data">
9 <p>
10 <input type="text" name="user" placeholder="用户名" />
11 </p>
12 <p>
13 <input type="password" name="pwd" placeholder="密码" />
14 </p>
15 <input type="submit" value="提交"/>
16 </form>
17 </body>
18 </html>
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <style>
7 body {
8 margin: 0;
9 }
10
11 .menu {
12 display: block;
13 padding: 5px;
14
15 }
16 </style>
17 </head>
18 <body>
19 <div style="height: 48px;background-color: antiquewhite;color: burlywood">
20 oms后台
21 </div>
22 <div>
23 <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: sandybrown;">
24 <a class="menu" href="/app2/user_info/">用户管理</a>
25 <a class="menu" href="/app2/user_group/">用户组管理</a>
26 </div>
27 <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
28 <h3>添加用户</h3>
29
30 <form method="POST" action="/app2/user_info/">
31 <input type="text" name="user"/>
32 <input type="text" name="pwd"/>
33 <input type="submit" value="添加"/>
34 </form>
35
36 <h3>用户列表</h3>
37 <ul>
38 {% for row in user_list %}
39 <li>
40 <a href="/app2/userDetail-{{ row.id }}">{{ row.username }}</a> |
41 <a href="/app2/userDel-{{ row.id }}">删除</a> |
42 <a href="/app2/userEdit-{{ row.id }}">编辑</a>
43 </li>
44 {% endfor %}
45 </ul>
46 </div>
47
48 </div>
49
50 </body>
51 </html>
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <style>
7 body{
8 margin: 0;
9 }
10 .menu{
11 display: block;
12 padding: 5px;
13
14 }
15 </style>
16 </head>
17 <body>
18 <div style="height: 48px;background-color: antiquewhite;color: burlywood">
19 oms后台
20 </div>
21 <div>
22 <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: sandybrown;">
23 <a class="menu" href="/app2/user_info/">用户管理</a>
24 <a class="menu" href="/app2/user_group/">用户组管理</a>
25 </div>
26 <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
27 <h1>编辑用户</h1>
28 <form method="post" action="/app2/userEdit-{{ obj.id }}/">
29 <input style="display: none" type="text" name="id" value="{{ obj.id }}" />
30 <input type="text" name="username" value="{{ obj.username }}" />
31 <input type="text" name="password" value="{{ obj.password }}"/>
32 <input type="submit" value="提交" />
33 </form>
34 </div>
35
36 </div>
37
38 </body>
39 </html>
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <style>
7 body{
8 margin: 0;
9 }
10 .menu{
11 display: block;
12 padding: 5px;
13
14 }
15 </style>
16 </head>
17 <body>
18 <div style="height: 48px;background-color: antiquewhite;color: burlywood">
19 oms后台
20 </div>
21 <div>
22 <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: sandybrown;">
23 <a class="menu" href="/app2/user_info/">用户管理</a>
24 <a class="menu" href="/app2/user_group/">用户组管理</a>
25 </div>
26 <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
27 <h1>用户详细信息</h1>
28 <h5>id:{{ obj.id }}</h5>
29 <h5>name:{{ obj.username}}</h5>
30 <h5>password:{{ obj.password }}</h5>
31 </div>
32
33 </div>
34
35 </body>
36 </html>
2、app中的models.py:
1 from django.db import models
2 # Create your models here.
3
4
5 class UserInfo(models.Model):
6 # id列,Django框架会默认生成id(自增,主键),也可以通过AutoField类型自定义主键,不过Django框架默认生成ID列会失效
7 # 用户名列,字符串类型,最大长度长度
8 username = models.CharField(max_length=32)
9 password = models.CharField(max_length=64)
2、app中的urls.py:
from django.conf.urls import url
from app2 import views
urlpatterns = [
url(r'^orm', views.orm_action),
url(r'^login', views.login),
url(r'^oms', views.oms),
url(r'^user_info', views.user_info),
url(r'^userDetail-(?P<nid>\d+)', views.user_detail),
url(r'^userDel-(?P<nid>\d+)', views.user_del),
url(r'^userEdit-(?P<nid>\d+)', views.user_edit),
]
3、app中的views.py:
1 from django.shortcuts import render
2 from django.shortcuts import redirect
3 from app2 import models
4
5
6 # 登录
7 def login(request):
8 if request.method == "GET":
9 return render(request, 'login.html')
10 elif request.method == "POST":
11 u = request.POST.get('user')
12 p = request.POST.get('pwd')
13 # 两种方式判断数据库中是否有匹配的数据
14 # obj = models.UserInfo.objects.filter(username=u,password=p).first() # 推荐这一种
15 # count = models.UserInfo.objects.filter(username=u, password=p).count()
16 obj = models.UserInfo.objects.filter(username=u, password=p).first()
17 if obj:
18 return redirect('/app2/user_info')
19 else:
20 return render(request, 'login.html')
21 else:
22 # PUT,DELETE,HEAD,OPTION...
23 return redirect('/login')
24
25
26 # 后台页面
27 def user_info(request):
28 if request.method == "GET":
29 user_list = models.UserInfo.objects.all()
30 print(user_list.query) # .query 查看原生sql语句
31 return render(request, "user_info.html", {"user_list": user_list})
32 elif request.method == "POST":
33 u = request.POST.get("user")
34 p = request.POST.get("pwd")
35 models.UserInfo.objects.create(username=u, password=p)
36 # 添加用户后返回添加页面查看新增数据
37 # 方式一
38 # user_list = models.UserInfo.objects.all()
39 # return render(request, "user_info.html", {"user_list": user_list})
40 # 方式二 有效避免重复代码
41 return redirect("/app2/user_info")
42
43
44 # 查看用户详情
45 def user_detail(request, nid):
46 # 取单条数据的两种方式
47 # 第一种(推荐)
48 obj = models.UserInfo.objects.filter(id=nid).first()
49 # 第二种(当数据为空,直接报错)
50 # models.UserInfo.objects.get(id=nid)
51 return render(request, "user_detail.html", {"obj": obj})
52
53
54 # 删除用户
55 def user_del(request, nid):
56 models.UserInfo.objects.filter(id=nid).delete()
57 return redirect("/app2/user_info")
58
59
60 # 编辑用户
61 def user_edit(request, nid):
62 if request.method == "GET":
63 obj = models.UserInfo.objects.filter(id=nid).first()
64 return render(request, "user_edit.html", {"obj": obj})
65 elif request.method == "POST":
66 user_id = request.POST.get('id')
67 u = request.POST.get('username')
68 p = request.POST.get('password')
69 models.UserInfo.objects.filter(id=user_id).update(username=u, password=p)
70 return redirect("/app2/user_info")
四、QuerySet方法详细
1、支持链式查询QuerySet方法:
1 def all(self)
2 # 获取所有的数据对象
3
4 def filter(self, *args, **kwargs)
5 # 条件查询
6 # 条件可以是:参数,字典,Q
7
8 def exclude(self, *args, **kwargs)
9 # 条件查询
10 # 条件可以是:参数,字典,Q
11
12 def annotate(self, *args, **kwargs)
13 # 用于实现聚合group by查询
14
15 from django.db.models import Count, Avg, Max, Min, Sum
16
17 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
18 # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
19
20 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) # 支持having子句,放在最开始的地方就是where子句,放在这边就是having子句
21 # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
22
23 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) # distinct=True去重
24 # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
25
26 def distinct(self, *field_names)
27 # 用于distinct去重
28 models.UserInfo.objects.values('nid').distinct()
29 # select distinct nid from userinfo
30
31 注:只有在PostgreSQL中才能使用distinct进行去重,不支持mysql数据库
32
33 def order_by(self, *field_names)
34 # 用于排序
35 models.UserInfo.objects.all().order_by('-id','age')
36
37 def reverse(self):
38 # 倒序
39 models.UserInfo.objects.all().order_by('-nid').reverse()
40 # 这个需要跟order_by配合使用,如果不存在order_by,则没有任何效果
41 # 如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
42
43 def defer(self, *fields):
44 #查询表中的数据,排除username、id列数据,将剩余列数据组合成querySet对象进行返回
45 models.UserInfo.objects.defer('username','')
46 models.UserInfo.objects.filter(...).defer('username','id')
47
48 def only(self, *fields):
49 #查询表中的数据,仅取username、id列中的数据组合成querySet对象进行返回,与defer相反
50 models.UserInfo.objects.only('username','id')
51 models.UserInfo.objects.filter(...).only('username','id')
52
53 def using(self, alias):
54 models.Blog.objects.filter(name="root").filter("id=1").all().using(alias="default1") #这个看你settings里面的设置
55 #指定使用的数据库进行操作(从settings中读取DATABASES配置),使用场景:比如数据库的读写分离,读的是A库,写的是B库
56
57
58 # 在原生的sql语句中会遇到一些复杂的sql,如msyql自定义的函数和过程、额外的查询条件、映射、子查询
59 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) #tables可不传,实例化的时候已传表名,order_by看使用场景使用
60
61 ## select与select_params配合,以%s进行传参,参数可以是元组,是可迭代的序列即可
62 Entry.objects.extra(select={'new_id': "%s"}, select_params=(1,))#select的参数,%s 就会替换成 1
63 #select *,1 as cid from Entry
64 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
65 #select *,(select col from sometable where nid = 1) as new_id from Entry
66 Entry.objects.extra(select={'new_id': "func(1)"}) #可以直接放函数
67 #select func(1) as new_id
68
69
70 ##where与params配合,加额外的where条件语句,以%s进行传参,参数可以是元组,是可迭代的序列即可
71 Entry.objects.extra(where=["name='a' OR age = 22"]) # or
72 Entry.objects.extra(where=["age = 22", "name='a'"]) # and
73 Entry.objects.extra(where=["func(arg)=2000"], params=['5'])
74 Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
75
76
77 #性能相关的内置方法
78 def select_related(self, *fields)
79 #1、
80 users = User.objects.all()
81 for row in users:
82 #仅仅是用户表的数据不会再去请求数据库,user_type表需要再次发送请求,但是如果这边10条用户表的数据有十条,总共就会请求10+1次数据库
83 print(row.name,row.sex)
84 print(row.ut.type_name) #再次请求一次数据库
85
86 #2、
87 users = User.objects.all().values("name","sex","ut__type_name") #如果是这种的话,就会只请求一次数据库,但数据不是querySet对象类型
88
89 #3、
90 #只拿ut对应的user_type表一次性拿过来
91 users = User.objects.all().select_related("ut") #只关联ut这张表,取出来,其他的表都不关联,因为一张表里面可以有多个外键
92 for row in users:
93 print(row.name,row.sex)
94 print(row.ut.type_name)
95 print(row.tu.name) #tu没有加进去,所以这边会再次django发送数据库请求
96
97
98
99 def prefetch_related(self, *lookups)
100 #一般在生产环境,很少连表查询,因为这样效率很低,我们一般都是空间换时间,所以这个就会用到prefetch_related,用到这个,会做多次查询,保证每次都是单表查询
101 users = User.objects.filter(ut_id__gt=30).prefetch_related('ut') #这边也可以多加几个外键
102 #解析步骤
103 ## select * from users where id > 30 当然这边不会用*的,一般会把所有字段都打印出来,效率更高
104 ## 获取上一步中所有ut_id = [1,2]的数据
105 ## select * from user_type where id in [1,2]
106 #这边django已经通过以上步骤,把要查询的数据放到内存中,所有就不用向数据库发送请求了,就可以直接从内存中获取
107 for row in users:
108 print(row.name,row.sex)
109 print(row.ut.type_name)
2、不支持链式查询QuerySet方法:
1 def raw(self, raw_query, params=None, translations=None, using=None):
2 # 执行原生SQL
3 models.UserInfo.objects.raw('select * from userinfo')
4 #obj = User.objects.raw('select id,name,password from tb ')
5
6 # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名,
7 models.UserInfo.objects.raw('select id as nid from 其他表')
8 #可以下面的方式将tb2里面的数据复制在tb中
9 #obj = User.objects.raw('select nid as id,username as name,email as password from tb2 ')
10
11 # 为原生SQL设置参数
12 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
13
14 # 将获取的到列名转换为指定列名
15 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
16 Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
17
18 # 指定数据库
19 models.UserInfo.objects.raw('select * from userinfo', using="default")
20
21 ################### 原生SQL ###################
22 from django.db import connection, connections
23 cursor = connection.cursor() # cursor = connections['default'].cursor()
24 cursor.execute("""SELECT * from auth_user where id = %s""", [1])
25 row = cursor.fetchone() # fetchall()/fetchmany(..)
26
27
28 def values(self, *fields):
29 # 获取每行数据为字典格式
30
31 def values_list(self, *fields, **kwargs):
32 # 获取每行数据为元祖
33
34 def dates(self, field_name, kind, order='ASC'):
35 # 根据数据库中时间列名进行某一部分进行去重查找并截取指定内容
36 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
37 # order只能是:"ASC" "DESC"
38 # 并获取转换后的时间
39 - year : 年-01-01
40 - month: 年-月-01
41 - day : 年-月-日
42
43 models.DatePlus.objects.dates('ctime','day','DESC')
44
45 def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
46 # 根据数据库中时间列名进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
47 # kind只能是 "year", "month", "day", "hour", "minute", "second"
48 # order只能是:"ASC" "DESC"
49 # tzinfo时区对象
50 #指定时区需要下载pytz库
51 """
52 pip3 install pytz
53 import pytz
54 pytz.all_timezones
55 pytz.timezone(‘Asia/Shanghai’)
56 """
57 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
58 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
59
60
61
62 def none(self):
63 # 返回一个空QuerySet对象
3、数据库操作:
如:批量插入数据库,对整个数据做聚合操作
1 def aggregate(self, *args, **kwargs):
2 # 聚合函数,获取字典类型聚合结果
3 from django.db.models import Count, Avg, Max, Min, Sum
4 result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) # distinct=True 先去重,再执行聚合 相当于sql如下: #select count(nid) as n from user
5
6 def count(self):
7 # 获取个数
8
9 def get(self, *args, **kwargs):
10 # 获取单个对象
11
12 def create(self, **kwargs):
13 # 创建对象
14
15 def bulk_create(self, objs, batch_size=None):
16 # 批量插入
17 # batch_size表示一次插入的个数
18 objs = [
19 models.DDD(name='r11'),
20 models.DDD(name='r22')
21 ]
22 models.DDD.objects.bulk_create(objs, 10)
23
24 def get_or_create(self, defaults=None, **kwargs):
25 # 如果存在,则获取,否则,创建
26 # defaults 指定创建时,其他字段的值
27 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
28
29 def update_or_create(self, defaults=None, **kwargs):
30 # 如果存在,则更新,否则,创建
31 # defaults 指定创建时或更新时的其他字段
32 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
33
34 def first(self):
35 # 获取第一个
36
37 def last(self):
38 # 获取最后一个
39
40 def in_bulk(self, id_list=None):
41 # 根据主键ID进行查找
42 id_list = [11,21,31]
43 models.DDD.objects.in_bulk(id_list) #相当于in操作
44
45 def delete(self):
46 # 删除
47
48 def update(self, **kwargs):
49 # 更新
50
51 def exists(self):
52 # 是否有结果
53
54 METHODS THAT DO DATABASE QUERIES
4、QuerySet序列化:
1 #第一种
2 ##使用Django内置的方法对queryset类型的数据进行序列化
3
4 from django.core import serializers
5 ret = models.BookType.objects.all()
6 data = serializers.serialize("json", ret)
7
8
9 #第二种
10 ##使用json.dumps对queryset类型的数据进行序列化
11 ####当list中queryset类型中没有复杂的数据类型(如:时间类型)可以直接使用json.dumps
12 import json
13 #ret = models.BookType.objects.all().values('caption')
14 ret = models.BookType.objects.all().values_list('id','caption')
15 ret=list(ret)
16 result = json.dumps(ret)
17
18 ####当list中queryset类型中没有复杂的数据类型(如:时间)可以直接使用json.dumps
19 import json
20 from datetime import date
21 from datetime import datetime
22
23 #自定义encoder
24 class JsonCustomEncoder(json.JSONEncoder):
25
26 def default(self, field):
27
28 if isinstance(field, datetime.datetime):
29 return field.strftime('%Y-%m-%d %H:%M:%S')
30 elif isinstance(field, date):
31 return field.strftime('%Y-%m-%d')
32 else:
33 return json.JSONEncoder.default(self, field)
34
35 #再序列化带有类似于ctime复杂的数据类型
36 ret = models.BookType.objects.all().values_list('caption','ctime')
37
38 ret=list(ret)
39
40 result = json.dumps(ret, cls=JsonCustomEncoder)
五、Model利用钩子进行数据验证(弱)
django Model也是支持数据验证的,只是这个数据验证比较弱而已,只能支持单个的验证,但是对于组合的、固定的,就无法进行相关数据验证了
1、models.py
class User(models.Model):
name = models.CharField(max_length=32,db_index=True) #创建索引
email = models.EmailField(max_length=30)
#Model通过clean()函数设置钩子
def clean(self): #Model内部对所有字段进行正则验证,完毕之后才会执行这个clean方法
from django.core.exceptions import ValidationError
c = User.objects.filter(name=self.name).count()
if c:
raise ValidationError
2、views.py
from app01 import models
def index(request):
obj = models.User(name="root",email="root")
obj.full_clean() #没有这个,name是不做验证的,有了full_clean是需要做验证的,验证不通过是要报错的,所以验证的时候,我们直接自己抓异常,进行异常处理
obj.save()
return HttpResponse("hello")
来源:oschina
链接:https://my.oschina.net/u/4362484/blog/4234086