一、数据库表的创建
这里需要注意的是如果我们连接的是MySQL数据库,那么就需要我们自己预先创建好数据库,这里我们使用model操作不能够创建数据库,只能够创建相应的表结构。
models中与数据库中对应的关系
类 -----> 数据表(数据库中的表)
对象(相当于我们实例化上面的类,也就是我们使用语句添加数据) -----> 数据行(表中的一行行数据)
属性(可以通过对象获取到相应的属性如id,name...) -----> 字段 (表中的一列列的如id,name...)
基本的结构
from django.db import models class userinfo(models.Model): # 如果没有models.AutoField,默认会创建一个id的自增列 username = models.CharField(max_length=32) # models.CharField 这个就是后面说的字段,括号里面的参数就是字段的参数 password = models.CharField(max_length=32) email = models.EmailField()
字段解释
1、models.AutoField 自增列 ---> int(11) 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。 2、models.BigAutoField 2、models.CharField 字符串类型 必须有 max_length 参数 表示的是字符的长度 3、models.BooleanField 布尔类型 ---> tinyint(1) 不能为空,Blank=True 4、models.ComaSeparatedIntegerField 用逗号分割的数字--->varchar 继承CharField,所以必须有 max_lenght 参数 5、models.DateField 日期类型 ---> date 对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。 6、models.DateTimeField 日期类型 ---> datetime 同DateField的参数 7、models.Decimal 十进制小数类型 ---> decimal 必须指定整数位max_digits和小数位decimal_places 8、models.EmailField 字符串类型(正则表达式邮箱)---> varchar 对字符串进行正则表达式,Django Admin以及ModelForm中提供验证机制 9、models.FloatField 浮点类型 ---> double 10、models.IntegerField 整形 11、models.BigIntegerField 长整形 integer_field_ranges ={ 'SmallIntegerField':(-32768,32767), 'IntegerField':(-2147483648,2147483647), 'BigIntegerField':(-9223372036854775808,9223372036854775807), 'PositiveSmallIntegerField':(0,32767), 'PositiveIntegerField':(0,2147483647), } 12、models.IPAddressField 字符串类型(ip4正则表达式) Django Admin以及ModelForm中提供验证 IPV4 机制 13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的) Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置报错 14、models.NullBooleanField 允许为空的布尔类型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 字符串类型 Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) 18、models.SmallIntegerField 数字 数据库中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 文本类型 20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串类型 正则表达式,Django Admin以及ModelForm中提供验证 URL 22、models.BinaryField 二进制 23、models.ImageField 字符串 路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) 24、models.FilePathField 字符串类型 Django Admin以及ModelForm中提供读取文件夹下文件的功能
字段中的一些参数
1、null=True 数据库中字段是否可以为空 2、blank=True django的Admin中添加数据时是否可允许空值 3、primary_key =False 主键,对AutoField设置主键后,就会代替原来的自增 id 列 4、auto_now 和 auto_now_add auto_now 自动创建---无论添加或修改,都是当前操作的时间 auto_now_add 自动创建---永远是创建时的时间 5、choices GENDER_CHOICE =( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 表示字符的长度 7、default 默认值 8、verbose_name Admin中字段的显示名称 9、name|db_column 数据库中的字段名称 10、unique=True 不允许重复,唯一性 11、db_index =True 数据库索引 12、editable=True 在Admin里是否可编辑 13、error_messages=None 错误提示 14、auto_created=False 自动创建 15、help_text 在Admin中提示帮助信息 16、validators=[] 17、upload-to
下面是关于数据库的一个示列图书管理系统。
这里面有:出版社,书籍,作者
这里我们可以知道一个出版社可以出版多个书籍,但是一个书籍只能有一个出版社。所以出版社和书籍是一对多的关系。
书籍和作者我们可以知道一本书可以有多个作者,一个作者可以写多本书,所以书籍和作者之间是多对多的关系。
一对多
class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) addr = models.CharField(max_length=128) # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher")
一对多我们只需要在对应关系的多的一个表中加入一个外键字段这个外键关联那个一的表也就是书籍关联出版社。
多对多的关系的创建
from django.db import models # Create your models here. # 图书管理系统, 书 作者 出版社 # 出版社 class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) addr = models.CharField(max_length=128) # 方式一 # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") # 这个在表里面会自动生成一个为publisher_id的字段 # 作者表 class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) # 告诉ORM 我这张表和book表是多对多的关联关系,ORM自动帮我生成了第三张表 book = models.ManyToManyField(to="Book") #这样会自动生成的表名为:book_author表,同时会有id、author_id、book_id这些字段 #同时我们在进行数据查询的时候不能够直接操作这个自动生成的表只有间接操作。 # # 方式二 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") # 作者表 class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) #自己创建第三张表创建第三张表来关联这两张表 class Author_Book(models.ManyToManyField): id = models.AutoField(primary_key=True) author = models.ForeignKey(to='Author') book = models.ForeignKey(to='Book') #自动在表中生成字段 author_id、book_id的字段。 #这个我们自己创建的第三方表我们可以直接操作,不同于自动创建的第三张表。 #这里我们还可以看出自己创建的第三方表我们可以自己再加一些字段到里面。 #而自动创建的第三方表,它的字段是固定。 #上面可以看出自己创建的第三方表比自动创建的第三方表好些
自动生成的第三章表的操作
obj =models.Application.objects.get(id=1) # 具体的对象
obj.r.add(1) :表示创建Application表的id=1和host表中的id=1创建一个对应关系
obj.r.add(2) :表示创建Application表的id=1和host表中的id=1创建一个对应关系
obj.r.add(1,2,3,4):表示增加多个对应关系 相当于创建 1-1 ,1-2,1-3,1-4的对应关系
obj.r.add(*[1,2,3,4]):表示增加多个对应关系,和上面一样
obj.r.remove(*[1,2,3,4]):表示删除多个对应关系
obj.r.clear():这样会删除Application中id=1的对应关系都会给清空
obj.r.set([3,5,7]):这样表示更新,将原有的关系删除,然后只有和3,5,7的对应关系
obj.r.all():这里获得是所有相关的主机对象的“列表”即QuerySet类似列表(操作和列表一样)里面的元素是对象。
上面我们可以看出当我们多对多关系,创建的方式有两种这个可以根据以后需求使用,
上面的表创建完后我们可以在当前项目的manage.py的同级目录下执行两个命令
1、python3 manage.py makemigrations
这个命令就是把我们对数据库中表的更改记录下来,并放在app目录下的migrations目录下
2、python3 manage.py migrate
这个是把上面记录下来的数据翻译成数据库语言,在数据库中执行相当于把更改后的数据平移到数据库中。
还有一种我们可以在pycharm下面完成上面操作如下:
这样会出来一个控制台只要在里面输入,makemigrations 和 migrate。和上面等同效果。这个还会出现提示输入。
Django 的ORM的一些操作。
必须会的几种操作
1、all() ----> 查询所有的结果,得到的是一个列表中元素是对象的返回值(下面统一叫对象列表) lis_obj = models.Author.objects.all() print('*'*10) print(type(lis_obj)) print('*' * 10) print(lis_obj) print('*' * 10) return HttpResponse("OK") #输出的结果为 ********** <class 'django.db.models.query.QuerySet'> ********** <QuerySet [<Author: Author object>, <Author: Author object>, <Author: Author object>]> ********** <class 'django.db.models.query.QuerySet'>这个和列表的操作差不多这里暂且叫做列表 使用all得到的返回值输出后,我们可以看到返回的是一个列表中元素为对象的返回值。 这里面的对象就是数据行一个对象代表查询的表的一行数据,通过对这个对象操作取到相应的字段的值 如: print(lis_obj[0].name) (在views.py中的使用) 返回的是Author表中第一行数据中字段为name的数据。这里的操作符合python的操作 lis_obj[0]表示取lis_obj列表中的第一个对象,lis_obj[0].name对象中的name属性值 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
上面返回的是一个QuerySet对象(也就是对象列表)的方法有:
all()
filter()
exclude()
order_by()
reverse()
distinct()
返回的是具体对象的方法有
get() :
first() :
last()
返回布尔值的方法有
exists()
返回数字的方法有
count()
特殊的QuerySet
values() 返回是一个字典为元素的列表(字段为key,字段的值为value)这个方法只能在对象列表(列表中的元素为对象)中使用
values_list() 返回是一个元组为元素的列表(只返回字段的value,没有key所以只能按顺序取)
单表查询双下划线
models.class_name.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.class_name.objects.filter(id__lt=10) # 获取小于10的值 models.class_name.objects.filter(id__lte=10) # 获取小于等于10的值 models.class_name.objects.filter(id__gt=2) # 获取大于2的值 models.class_name.objects.filter(id__gte=2) # 获取大于等于2的值 models.class_name.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.class_name.objects.exclude(id__in=[11, 22, 33]) # not in models.class_name.objects.filter(name__contains="ven") # 获取name字段包含"ven"的 models.class_name.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.class_name.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 类似的还有:startswith,istartswith, endswith, iendswith date字段还可以: models.Class.objects.filter(first_day__year=2017) 上面的获得的是一个对象列表
ForeignKey(外键)操作
正向查找
对象跨表查找 在app下的models class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) # addr = models.CharField(max_length=128) # 方式一 # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") 在app下的views def test(request): book_obj = models.Book.objects.first() # 找到的是书籍表中的第一本书的对象 print(book_obj.publisher) # 找到这本书关联的出版社对象,获取跨表关联的对象 print(book_obj.publisher.name) # 使用出版社对象获取里面的属性name return HttpResponse("OK") 字段查找(跨表) 关联字段__字段 print(models.Book.objects.values_list('publisher__id')) print(models.Book.objects.values('publisher__id'))
上面的查找只能从有Foreignkey字段的表中跨表查找,不能够从被关联的表中反向查找
反向操作
# 这里书籍和出版社是多对一的关系 # obj.表名_set # publisher_obj = models.Publisher.objects.first() # 得到第一个出版社的对象 # books = publisher_obj.book_set.all() #获取这个出版社对象所有的书籍对象 # title = books.values_list('title') # 获取该出版社所有书籍的名字返回的是一个元素为元组的列表 # print(title) # 表名__字段 # titles = models.Publisher.objects.values_list("book__title")
反向查找的时候我们还可以在设置外键的时候加上一个字段related_name='自己这张表起一个名字' 这个名字是代替表名_set()
查询语句为:publisher_obj = models.Publisher.objects.first() # 得到第一个出版社的对象
ret = publisher_obj.books.all() 通过我们的别名直接在对象中通过.别名.all()得到所有关联的列表对象。
多对多关系(ManyToManyFiled)
"关联管理器"是一对多和多对多关联上下文中使用的管理器
存在的两种情况:
1.外键关系的反向查询
2.多对多关联关系
多对多的一些方法
create()
通过一个现有对象创建一个关联的对象,
如:用书和作者这个是多对多关系,我们用现有的作者来创建一本新的书并把两者关联起来。
相当于我们现在书的列表中创建一个书的数据,在在第三张关联的表中把这本书合 作者关联起来。
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象
添加一本书
models.Author.objects.first().book_set.create(title="学习go语言", publish_id=1)
上面就是添加一本书这本书关联了第一个作者和关联id为的出版社。
后面创建的书书里面有什么字段就写什么字段。
add()
把指定的model对象添加到关联对象集中
author_objs = models.Author.objects.get(id=3) 查找到id等于3的作者的所有对象
models.Book.objects.first().author_set.add(author_objs) 这里的意思把上面的作者对象和第一本书关联
如果关联多个的话。
author_objs = models.Author.objects.filter(id__lt=3) 查找到id小于3的作者的所有对象
models.Book.objects.first().author_set.add(*author_objs) 这里的意思把上面的所有的作者对象和第一本书关联
直接添加id
models.Book.objects.first().authors.add(*[1, 2]) 直接把作者的id关联
set()
更新model对象的关联对象。
book_obj = models.Book.objects.first()
book_obj.authors.set([2, 3])
remove()
从关联对象集中移除执行的model对象
book_obj = models.Book.objects.first()
book_obj.authors.remove(3) 这里面的值也可以填写具体对象
clear()
从关联对象集中移除一切对象。
book_obj = models.Book.objects.first()
book_obj.authors.clear()
注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
应为默认这项是不能为空的,当我们去除关联关系时,那ForeigKey这项就是空了,就会和默认不为空有冲突就会报错。
聚合查询和分组查询
聚合
from django.db.models import Avg,Sum,Max,Min
avg_book = models.Book.objects.all().aggregate(Avg('price'),Min('price')) # 所有书籍的平均价格,和最小的价格。这个里面有多个求值
这个得到的是一个字典{'price__avg': 算出来的平均值,'price__mix':Decimal('19.90')}
上面我们也可以给这个起名字
avg_book = models.Book.objects.all().aggregate(a = Avg('price'),Min('price'))
这个得到的是一个字典{'a': 算出来的平均值,'price__mix':Decimal('19.90')}
分组
from django.db.models import Avg,Sum,Max,Min,Count
一、统计一本书它的作者个数
book_list_obj = models.Book.objects.all().annotate(author_num=Count("author"))
上面是以每本书作为分组,统计每一本书的作者数量,在这个得到一个列表里面的元素是每一本书的对象,且这个对象比原先多了一个author_num属性
for obj in book_list_obj:
print(obj.title,obj.author_num) 这个输出的是表中每一本书的名字以及这本书有多少作者。
我们也可以得到一个列表列表中的元素为字典的返回值
book_list_dic = models.Book.objects.all().annotate(author_num=Count("author")) .values('title','author_num')
字典中的键只有'title'和'author_num'。
二、统计出每个出本社卖的最便宜的书的价格
publisher_list_obj = models.Publisher.objects.annotate(min_price=Min("book__price"))
一每一个出版社作为分组,上面的book__price是跨表查询书的价格
字典微元素的列表返回值
publisher_list_obj = models.Publisher.objects.annotate(min_price=Min("book__price")).value()
三、统计作者数目大于一的书籍
print(models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1) ) 输出的是一个元素为对象的列表
models.Book.objects.annotate(author_num=Count("author"))这个表示以书为分组找到所有的书有多少作者
.filter(author_num__gt=1)这个表示筛选条件山选出书的作者数目大于一
四、根据一本图书作者数量的多少对查询集 QuerySet进行排序
print(models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")) 输出的是一个元素为对象的列表
五、查询各个作者出的书的总价格
print(models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")) 输出的是元素为字典的列表
F查询和Q查询
F查询
1、查询评书的卖出大于库存的书籍
from django.db.models import F
print(models.Book.objects.filter(sale__gt=F('repertory')).values()) #得到的是一个元素为字典的列表
上面的黄色部位就是卖出的大于库存的。
2、Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作
models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
3、修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)
4、给每一本书的名字后面加上"第一版"
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F("title"), Value("第一版")))
Q查询
一、查询书的卖出卖出数量大于1000,或者价格小于100的所有书
from django.db.models import Q
models.Book.objects.filter(Q(sale__gt=1000) | Q(price__lt=1000))
二、Q查询和字段查询同时存在时,字段查询要放在Q查询后面
models.Book.objects.filter(Q(sale__gt=1000) | Q(price__lt=1000),title__contains='小黑')