Django5_model模型

一.ORM
ORM:Object Relational Mapping(关系对象映射)
我们通过写的类来表示数据库中的表;
我们根据这个类创建的对象是数据库表里的一行数据;
作用:为了实现面向对象的编程语言里不同类型系统的数据之间进行转换,即:用面向对象的方式去操作数据库进行创建表及增删改查等操作;
好处:1.ORM使得我们通用的数据库进行交互是变得简单易行,而且完全不用考虑不同的SQL语句。能够快速开发;2.可以避免一些对数据库操作不熟带来的由于手写sql语句带来的性能问题;
二.Django不能数据库的使用
1.django默认使用sqlite数据库驱动引擎(不用进行任何配置),如果要使用MySQL数据库,则需要修改ettings.py中的DATABASES;

十载的建德网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。营销型网站的优势是能够根据用户设备显示端的尺寸不同,自动调整建德建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。成都创新互联公司从事“建德网站设计”,“建德网站推广”以来,每个客户项目都认真落实执行。

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'day70',
    'USER': 'eric',
    'PASSWORD': '123123',
    'HOST': '192.168.182.128',
    'PORT': '3306',
    }
}

2.若查看orm操作执行的原生SQL语句,在project中的settings.py文件增加配置文件

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

3.修改project 中的initpy 文件设置 Django默认连接MySQL的方式:

import pymysql
pymysql.install_as_MySQLdb()

三.表的创建
A.首先在项目的setting文件中设置DATABASES的参数(数据库参数配置);
B.如果是非sqlite数据库,则需要在对应的app应用下导入对应的数据库模块;
C.在对应APP应用下的model下添加需要创建表对应的classs;
1.单表的创建

class Userinfo(models.Model):
    username = models.CharField(max_length=256,primary_key=True)
    password = models.CharField(max_length=256)
    address = models.CharField(max_length=256)
    age = models.IntegerField()

2.一对多表的创建

class Book(models.Model):
    # 从表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

3.多对多表的创建
3.1方式1:使用ManyToManyField()方法进行关联多对多(此时在django中会自动生成第三张表book_author)

from django.db import models

# Create your models here.
class Book(models.Model):
    # 从表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    #创建Book和Authors的多对多关系
    authors = models.ManyToManyField("Authors")

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

Django5_model模型
3.2方式2:不使用ManyToManyField()方法,手动创建第三张book_author关联的表(一对多的关系)

from django.db import models
# Create your models here.
class Book(models.Model):
    # 从表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
#手动创建第三张关联Book和Author的表Book_Author(此时ManyToManyField()不能再用)
class Book_Author(models.Model):
    bookid = models.ForeignKey("Book",on_delete=models.CASCADE)
    authors = models.ForeignKey("Authors",on_delete=models.CASCADE)

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

Django5_model模型
四.单表数据库增删改查
2.1增:向数据库中添加数据
方式1.使用model中的对象并结合object的create方法
Userinfo.objects.create(username ='username',password = 'password',address = 'address',age = 34)
方式2.使用model中的类进行实例化进行操作
该方法是先使用model类进行实例化,再使用save进行保存

user = Userinfo(username = 'username',password = 'password',address = 'address',age = 'age')
 user.save()

2.2删:删除数据库中的数据(先使用filter进行查询再删除)
Userinfo.objects.filter(username=username).delete()
2.3改:修改数据库中现有的数据(先使用filter进行查询再进行修改)
方式1:

Userinfo.objects.filter(username=username).update(password="password",address = "address")
Sql:update tablename set password="password",address = "address" where username=username

方式2:

User = Userinfo.objects.filter(username=username)
User.password="password"
User.address ="address"
User.save()
Sql:update tablename set password="password",address = "address",age = "age" where username=username

方式1与方式2的区别:
方式1只修改指定的字段值,而方式2会修改所有字段的值(指定了新值则使用新值,没有新值则使用原有的值);方式2操作更复杂且效率低;
2.3查:按照条件查询数据库
A.判断查询结果是否有值(结果为布尔值,查询结果又记录返回Ture,否则返回False)
Userinfo.objects.filter(username=request.POST.get('username')).exists()
B.查询某个表的所有记录
Userinfo.objects.all()
C.查询某个表结果的N条记录

Userinfo.objects.all()[0]
Userinfo.objects.all()[:]
Userinfo.objects.all()[:4]
Userinfo.objects.all()[: : 1]
Userinfo.objects.all()[:4: -1]
Userinfo.objects.first()--获取查询结果第1条,结果为实例对象
Userinfo.objects.laset()--获取查询结果最后1条,结果为实例对象

D.查询字段值等于某个值(=)

Userinfo.objects.filter(username=username)

E.查询字段值不等于某个值(!=)

Userinfo.objects.exclude(username='admin1')

F.查询字段值包含某些值(in)

Userinfo.objects.filter(age__in =[34,55,56])
Sql: select * from table where age in (34,55,56 )

G.查询字段值不包含某些值(not in)

Userinfo.objects.exclude(age__in =[34,55,56])
Sql: select * from table where age not in (34,55,56 )

H.查询字段值大于或大于等于某个值(>或>=)

Userinfo.objects.filter(age__gt =34)
Sql: select * from table where age > 34;
Userinfo.objects.filter(age__gte =34)
Sql: select * from table where age >= 34;

I.查询字段值小于或小于等于某个值(<或<=)

Userinfo.objects.filter(age__lt =34)
Sql: select * from table where age < 34;
Userinfo.objects.filter(age__lte =34)
Sql: select * from table where age <= 34;

J.查询字段值包含某个值(like)
1.不忽略大小写的模糊查询 like ‘%zh%’

Userinfo.objects.filter(username__contains ='zh')

2.忽略大小写的模糊查询 忽略大小写 like ‘%zh%’

Userinfo.objects.filter(username__icontains ='zh')

3.以...开头

Userinfo.objects.filter(username__startswith = 'z')

4.以...开头并忽略大小写

Userinfo.objects.filter(username__istartswith = 'z')

5.以...结尾

Userinfo.objects.filter(username__endswith ='g')

6.以...结尾并忽略大小写

Userinfo.objects.filter(username__iendswith ='g')

注:对于sqlite来说,contains的作用效果等同于icontains
K.查询字段值不包含某个值(not like)

Userinfo.objects.exclude(username__contains = 'zh')

L.查询字段值在某个范围之内(between and)

方式1.Userinfo.objects.filter(age__gt = 30,age__lt = 60)
方式2.Userinfo.objects.filter(age__range = [34,56])(包含边界)

M.查询需要字段的结果

方式1:
Userinfo.objects.filter(username=username).values("username","password","address","age")
得到的是一个QuerySet(字典类型)类型的list
方式2:
Userinfo.objects.filter(username=username).values_list("username","password","address","age")
得到的是一个QuerySet(元组类型)类型的list

N.对查询结果去重

Userinfo.objects.filter(username__icontains='zh').distinct()
Sql:select distinct * from tablename where username like 'zh';

O.对查询结果进行统计

Userinfo.objects.filter(username__icontains='zh').count()
Sql:select count(*) from tablename where username like 'zh';

P.year 日期字段的年份
Q.month 日期字段的月份
R.day 日期字段的日
S.isnull=True/False
T.isnull=True 与 exact=None的区别

查询的另一种方式:

Userinfo.objects.get(username = 'zhang')

只使用于有且只有一个条结果,否则将会报错。
通过filter()方法和get()方法查询的区别:
1.filter()的查询结果可以为任意情况(可有,可无,可唯一,可多条);而get()方法只适用于只有一条结果的情况;
2.filter()得到的查询结果为一个QuerySet的list,而get()方法得到的结果为一个实例化的对象(不能进行遍历)

users = Userinfo.objects.get(username = 'zhang')
uame=users.username
users = Userinfo.objects.all()
uame2=users[0].username

五.一对多表的操作
A表中一条数据对应B表中N条数据,B表中已条数据只能对应A表中一条数据- - - -一对多;
Django5_model模型
Django5_model模型
多表操作也包含增删改查,主要与单表大致相同。注意一对多查询中的技巧即可。以下讲解查询的主要方法,也是多表操作中的重难点。
A.新增
方式1.直接给外键赋值对应的数值
新增
# 方式1.外键直接赋值数值

Book.objects.create(title = 'Javascript经典',price = 67.2,pub_date = '2017-12-02',publish_id =1)

方式2.给外键赋值对应的主键对象(django内部翻译对应的外键)

# 方式2.外键赋值对应的主键对象
publish = Publish.objects.get(name='清华出版社')
Book.objects.create(title='python从入门到放弃', price=87.2, pub_date='2014-12-02', publish=publish)

B.查询
1.查看属性值

books = Book.objects.get(title=bookname)
print("title=",books.title)

2.正向查询(通过从表外键属性查看主表的各个字段值)

books = Book.objects.get(title=bookname)
print("publish=",books.publish)
print("type=", type(books.publish))
print("publishname=",books.publish.name)    #正向查询

如图:
Django5_model模型
3.通过从表的外键查询对应的主表的对应内容

#方式1.通过从表的外键值等于主表的主键进行关联
bookpublishs = Publish.objects.filter(id = Book.objects.get(title=bookname).publish_id)
# 方式2.通过主表和从表的关联用从表的某一个字段来查询对应主表的信息
bookpublishs1  =  Publish.objects.filter(book__title__icontains='入门')

Django5_model模型
*4.通过主表来查询对应从表的信息(肯定多条结果)重点**

# 方式1.通过主表的主键与从表的外键相等的属性进行关联查询(复杂)
books = Book.objects.filter(publish_id=Publish.objects.get(name=publishname).id)
#方式2.通过从表外键属性来查询出对应主表主键对应的从表所有信息(即:查找出某出版社所有书籍的信息)(推荐使用)
books = Book.objects.filter(publish =Publish.objects.get(name = publishname))
# 方式3.通过主表查询所有对应从表的记录(obj_set关键字,推荐使用)
publish = Publish.objects.get(name = publishname)
books = publish.book_set.all()
#方式4.通过从表的外键之万能双下划线(__)进行关联主表查询
books1 = Book.objects.filter(publish__name=publishname)
# 方式5.通过主表和从表的关联用从表对象的万能双下划线(__)进行关联从表进行查询
booknames = Publish.objects.filter(name='南方出版社').values('book__title','book__price')

Django5_model模型
Django5_model模型
六.多对多表的操作
A.方式1(ManyToManyField()方法)关联

from django.db import models

# Create your models here.
class Book(models.Model):
    # 从表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

    #创建Book和Authors的多对多关系
    authors = models.ManyToManyField("Authors")

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

新增:

#新增Book和Authors之间的关联,即:新增第三张关联表的记录
#找到需要进行关联的book(进行关联时必须是一条记录)
book_obj = Book.objects.filter(title__contains='经典')[0]
# 找到book需要进行关联的authors
author_objs = Authors.objects.filter(age__lt=56)
author_obj = Authors.objects.get(id=1)      #得到一条记录
#将book和authors进行关联
book_obj.authors.add(*author_objs)#author_obj得到的是一个类似列表的集合,所以此处要在前面加*;如果得到的是一条记录则不用加*
book_obj.authors.add(author_obj)

查询:

#通过book查询authors
book = Book.objects.filter(id=1).all()[0]
authors = book.authors.all()
for i in range(len(authors)):
    print("book",authors[i].name,authors[i].age)

# 通过authors查询book
auth = Authors.objects.filter(id=1).all()[0]
book = auth.book_set.all()
for i in range(len(book)):
    print("book",book[i].title,book[i].publish)

# 查询'再遇未知的自己'书的作者
info =Authors.objects.filter(book__title='再遇未知的自己').values('name','age','book__title','book__price')

删除:

#同理,解除book和authors之间的关联
# 找到需要进行关联的book(进行关联时必须是一条记录)
book_obj = Book.objects.filter(title__contains='经典')[0]
# 找到book需要进行关联的authors
author_objs = Authors.objects.filter(age__lt=56)
author_obj = Authors.objects.get(id=1)  # 得到一条记录
#解除book和authors之间的关联
book_obj.authors.remove(author_obj)     #解除一条关联的记录(不带*)
book_obj.authors.remove(*author_objs)   #解除多条关联的记录(带*)
book_obj.authors.remove(3)      #解除一条关联的记录(authors_id = 3)

修改:
参考一对多表的修改操作
B.手动创建第三张关联表(Book_Author)进行关联(*不推荐使用)
说明:不推荐该种方式,因为通过手动创建第三张关联的表,将不会在Book表中创建author的实例属性,不能直接使用万能的’__’方式来通过book调用author的相关属性,不方便操作。

from django.db import models

# Create your models here.
class Book(models.Model):
    # 从表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

    #创建Book和Authors的多对多关系
    # authors = models.ManyToManyField("Authors")

#手动创建第三张关联Book和Author的表Book_Author(此时ManyToManyField()不能再用)
class Book_Author(models.Model):
    book = models.ForeignKey("Book",on_delete=models.CASCADE)
    authors = models.ForeignKey("Authors",on_delete=models.CASCADE)

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

新增:

Book_Author.objects.create(book_id = 1,authors_id=2)

查询:

#查询
#查询'再遇未知的自己'书的作者
#方式1:
book = Book.objects.get(title='再遇未知的自己')
authors =  book.book_author_set.all().values('authors__name')
# print("authors=",authors[0]['authors__name'])
# 方式2:
authors = book.book_author_set.all()[0].authors.name
#查询'刘汉英'出过的书
authors = Authors.objects.get(name='刘汉英')
book = authors.book_author_set.all().values('book__title','book__price')

修改:
删除:

七.model数据库的聚合函数及分组函数的使用方法
聚合函数包含:Sum() Max() Min() Avg() Count()......
分组函数: group by
Django中聚合函数的格式:
Book.objects.all().aggregate(自定义别名 = 聚合函数名称("字段名称"))
例如:

price = Book.objects.all().aggregate(Avg("price"))
sum = Book.objects.all().aggregate(Sum("price"))
count = Book.objects.all().aggregate(Count("price"))
max = Book.objects.all().aggregate(Max("price"))
min = Book.objects.all().aggregate(Min("price"))

price = Book.objects.filter(authors__name='刘汉英').aggregate(Avg("price"))

Django5_model模型

Django5_model模型

Django中分组函数的格式:
Book.objects.all().values("分组的字段").annotate(分组后需要查询的内容)
例如:

#查询所有作者所写书籍的总数/平均价格/总和
res = Book.objects.all().values("authors__name").annotate(Avg("price"),Count("price"),Sum("price"))
# print('res==',res)
# 查询所有作者所写书籍中价格大于50元的总数/平均价格/总和
res = Book.objects.filter(price__gt = 50).values("authors__name").annotate(Avg("price"), Count("price"), Sum("price"))
# print('res==', res)

#查询各个出版社最便宜书的价格
#错误写法:如果以book进行查询,则查询的结果会以书为主体,则当出版社未出版书时结果不显示出来(因为是以书为主体,而不是以出版社为主体的)
res = Book.objects.all().values("publish__name").annotate(Min("price"))
print("res=",res)
print('---'*20)
#正确写法,以publish为主体进行分组查询
res = Publish.objects.all().values('name').annotate(minprice = Min("book__price"))  #minprice自定义别名
print("res=", res)

Django5_model模型
八.F查询和Q查询
当我们需要把所有书籍的价格提高10元时,又该怎么操作呢?在sql中应该为:update book set price = (price+10)
Django5_model模型
此时我们可以考虑使用django中的F()函数 
作用:操作数据表中的某列值,F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用,不用获取对象放在内存中再对字段进行操作,直接执行原生产sql语句操作。通常情况下我们在更新数据时需要先从数据库里将原数据取出后方在内存里,然后编辑某些属性,最后提交。

#修改所有书籍的价格使其加价10元
Book.objects.all().update(price=F("price")+10)

Django5_model模型
在上面的所有场景中,我们在进行查询时的过滤条件(filter()函数))只使用了单条件或者多条件(and)查询,无法使用or 或者not进行查询。此时django提供了Q()函数来完成or 或 not功能。
作用:对对象进行复杂查询,并支持&(and),|(or),~(not)操作符。

#Q查询和关键字查询并用,注意此时必须Q()放在关键字前面,否则报错
#查询所有南方出版社出版且价格大于50的书籍
book1 = Book.objects.filter(Q(publish__name='南方出版社'),price__lt=50)
print("book1=",book1)
book2 = Book.objects.filter(price__lt=50,publish__name='南方出版社')
print('book2=',book2)

Django5_model模型

# 查询所有南方出版社出版或者价格大于100的书籍
book3 = Book.objects.filter(Q(publish__name='南方出版社')| Q(price__gt=100)).values("title")

Django5_model模型

# 查询所有南方出版社出版或者价格不大于100的书籍
book4 = Book.objects.filter(Q(publish__name='南方出版社')|Q(price__lte=100)).values("title")
print('book4=', book4)
book5 = Book.objects.filter(Q(publish__name='南方出版社') | ~Q(price__gt=100)).values("title")
print('book5=', book5)

Django5_model模型
九.QuerySet集合对象的特殊属性
1.不使用QuerySet时不进行查询数据库操作
Django5_model模型
2.同一个QuerySet,django有缓存不会重复操作数据库,直接读取缓存;如果中间修改了后面需要使用则应该重新查询获取QuerySet
Django5_model模型
Django5_model模型
Django5_model模型
QuerySet的特性:
1.可切片
2.可迭代性
可迭代性说明:django的QuerySet自带cache机制(缓存机制),它会把一次性查出的结果都放进缓存中,当数据量极大时会导致内存被极大的消耗,此时会严重影响性能。此时,我们可以考虑使用python的迭代器iterator()进行处理,这里每次只存储部分少量需要使用的数据在内存中,通过next()方法进行获取下次需要的数据。这样既可以满足需求,又可以节省内存。但是,使用iterator()并不会生成QuerySet缓存,可能会需要额外的查询数据库。exists()也是不会生成QuerySet缓存。
Django5_model模型
十.欢迎关注作者公众号
Django5_model模型


当前标题:Django5_model模型
文章源于:http://myzitong.com/article/piicid.html