django框架基础-ORM操作-长期维护-20191213

 

###############    ORM介绍和使用mysql的基本配置    ################

 

# ORM简介
# O是object,对象
# R是relation,关系,这是关系数据库中的表
# M是mapping,映射
# 在django里面主要是在models.py文件里面设计模型类,
###########################
# ORM另一个作用:根据设计的类生成数据库中的表
# django中使用ORM创建表
# 这种可以使用写Python语句,然后自动翻译成为sql语句,但是这种写的sql执行的效率和大神程序员写的还是有差距的,
# 类--数据表
# 对象--数据行
# 属性--字段,理清了这三点,ORM就没有问题
# ORM回顾,对象关系映射,object relational mapping,
# 优点:让软件开发人员专注于业务逻辑的处理,提高了开发效率。
# 缺点:一定程度上降低了程序的执行效率,有一个把orm翻译成sql的过程,如果一个公司对执行效率要求比较高

# 配置使用mysql数据库
# 第一步:在项目目录下-项目文件夹下-settings文件中,
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'XXX',
        'USER': 'root',
        'PASSWORD': 'XXX',
        'HOST': 'localhost',
        'PORT':3306,
    }
}
# 第二步:在项目目录下-项目文件夹下-__init__文件中,
import pymysql
pymysql.install_as_MySQLdb()

#创建数据库
# ORM可以操作数据表,操作数据行,但是不能创建数据库,需要自己创建数据库,这是使用mysql的情况下
# 如果你使用SQLite,你不需要事先创建任何东西 —— 数据库文件将会在需要的时候自动创建。
cmd
mysql -uroot -p
create database XXXXX;
use django
show tables;

 

###############   使用ORM创建表    ################

 

from django.db import models


class Publisher(models.Model):
    '''出版社表'''
    id = models.AutoField(primary_key=True)
    name=models.CharField(max_length=64,null=False,unique=True)
    addr=models.CharField(max_length=120,default='上地出版社')

    def __str__(self):
        # 返回出版社的名称
        return self.name
    class Meta:  # 定义一个元类
        db_table='Publisher'
        # 指定对应的表名
        # 工作中一定要指定表名,否则改动了程序app的名字,迁移的时候就会出问题,


class Book(models.Model):
    '''书籍表'''
    id = models.AutoField(primary_key=True)
    title=models.CharField(max_length=64,null=False,unique=True)
    # ForeignKey,出版社和书关系是一对多的关系,,使用外键ForeignKey,
    # to=Publisher,数据库中实际没有这个publisher,实际是这个publisher_id
    publisher=models.ForeignKey(to=Publisher,on_delete=models.CASCADE,related_name='books')
    price=models.DecimalField(max_digits=5,decimal_places=2,default=99.99)
    inventory_num=models.IntegerField(default=1000)
    sales_num=models.IntegerField(default=0)
    pub_data=models.DateField()

    def __str__(self):
        return self.title

class Author(models.Model):
    '''作者表'''
    name = models.CharField(max_length=64, null=False, unique=True)
    age = models.IntegerField(default=18)
    phone = models.BigIntegerField(default=18753333333)
    # ManyToManyField,作者和书之间是多对多关系
    # 在数据库中是通过第三张表建立多对多的关系的,
    book = models.ManyToManyField(to='book')
    detail=models.OneToOneField(to='AuthorDetail',null=True,unique=True)
    #一个作者对应一个作者详情,
    #为什么这么做,因为作者表用的非常的频繁,每一次查的时候都要全表查,数据量大,但是用到的字段不多,
    #所以把常用的字段抽离出来,比如列表页和详情页,这些都是需要分离的,为了更快的查询,

    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    hobby=models.CharField(max_length=32)
    addr=models.CharField(max_length=128)

 

执行命令:

# 执行命令,这样表就创建了
python manage.py makemigrations   #把改动记录到文件中,
python manage.py migrate  #迁移

# 在django中的ORM操作数据库表:
# 删除数据表,注释掉整个建表的类,
# 执行语句,这样就删除表了,
python manage.py makemigrations
python manage.py migrate

# 修改字段一样,修改表字段,
# 执行语句,
python manage.py makemigrations
python manage.py migrate

 

 ###############    django -ORM常用的字段和选项    ################

# ORM的具体使用:
# 定义模型类的时候,字段名的要求:
# 1,不能是python关键字,
# 2,字段名中不能出现连续的下滑线
# 语法:
# 属性名=models.字段类型(选项)
###############
# ORM里面的字段类型和选项:
# 1,ORM常用的字段
from django.db import models
class Test(models.Model):
    id = models.AutoField(primary_key=True)  # AutoField 自动增长的整型,primary_key 主键
    isnum=models.BooleanField()  # BooleanField 布尔字段,值为True或者False
    # isnum2=models.NullBooleanField  # NullBooleanField 支持null,True,False三种,这个一般不用
    name = models.CharField(max_length=20,unique=True)  # CharField 字符串,max_length最大长度
    text=models.TextField()  # 大文本字段,一般超过4000个字符串的时候使用,比如新闻内容
    age=models.IntegerField()  # IntegerField 整数 一个整数类型,范围在 -2147483648 to 2147483647。10位,所以不能用来存手机号,
    price=models.DecimalField(max_digits=10,decimal_places=2)  # DecimalField 十进制的浮点数,max_digits这是总位数,decimal_places这是小数位数
    # price2 =models.FloatField(max_digits=10,decimal_places=2)  # 这个和上面的那个精度不同,这个存进计算机和拿出来是有差异的,比不上DecimalField,只要是钱的问题,都是用DecimalField
    create_time=models.DateField(auto_now_add=True)  # DateField日期,auto_now_add,----每次新增的时候添加时间为当前时间,
    update_time = models.DateField(auto_now=True)  # DateField日期,auto_add----每次修改的时候更改时间,和auto_now_add这两个不能同时使用,
    time=models.TimeField()  # 参数同上,这是小时,分,秒,DateField这是年月日,
    data_time=models.DateTimeField(null=False)  # 参数同上,这是年月日,时分秒,
    file=models.FileField()  # FileField 上传文件字段,
    image=models.ImageField()  # 继承于FileField,对上传的内容进行校验,确保是一个图片

# 2,ORM常用的选项:
# default 设置默认值 eg:default="123"
# primary_key 设置主键 eg:primary_key=True
# unique 设置唯一值,eg:unique=True
# db_index 设置索引,eg:db_index=True,这就比如你查字典的时候先查索引,然后再往后查
# db_column 设置字段的名字,eg:db_column='title'这样生成表的时候,会按照这个名字
# null 设置是否为空,eg:null=True,默认是不能空的,
# blank 如果是True,就是这个字段允许是空白,默认是False,这个是后台管理页面表单验证范畴的,
# 注意:default和blank不影响表的结构,不需要做迁移,其他的都要迁移,

 

 ###############    django -ORM单表查询函数    ################

from app01 import models
from django.http import HttpResponse
from datetime import date
from django.db.models import Q
from django.db.models import F
from django.db.models import Sum, Min, Max, Count, Avg

def ORM(request):
    # ORM一般操作,必知必会13条:
    # 返回queryset对象的:
    all_book = models.Book.objects.all()  # 返回所有数据,结果是可以遍历的
    book1 = models.Book.objects.filter(id=1)  # 返回满足条件的数据
    book2 = models.Book.objects.values() # 这是把所有字段拿出来了,这是一个字典序列,values('name','create_time')  #可以指定字段,
    book3 = models.Book.objects.values_list() # values_list('name','create_time') #这是返回的一个元组,
    book4 = models.Book.objects.exclude(id=1)  # 返回不满足条件的数据
    # book5 = models.Book.objects.order_by('id')  # 对结果排序,升序
    # book5 = models.Book.objects.order_by('-id')  # 对结果排序,降序,在字段前面加减号,
    book5 = models.Book.objects.filter(id__lt=3).order_by('-id')  # 对过滤结果进行排序
    book6 = models.Book.objects.reverse()
    book7 = models.Book.objects.distinct()
    # 返回具体对象的:
    book8 = models.Book.objects.get(id=1)  # 查不到数据会报异常,所以一般不用这个,返回的结果中有且只有一条数据,有多条数据,也会报异常
    book9 = models.Book.objects.first()
    book10 = models.Book.objects.last()
    # 返回布尔类型
    book11 = models.Book.objects.exists()  # 判断查询集里面有没有数据,如果有就是True,没有就是False,括号里面不需要有值
    # 返回数量
    book12 = models.Book.objects.count()

    ##################################
    # 模糊查询:
    book13 = models.Book.objects.filter(title__contains='红')  # 包含红的,
    book14 = models.Book.objects.filter(title__endswith='志')  # 以志结尾的,
    book14 = models.Book.objects.filter(title__startswith='西')  # 以西开头的

    # 查询书名不为空的书
    book14 = models.Book.objects.filter(title__isnull=False)

    # 范围查询
    book14 = models.Book.objects.filter(id__in=[2, 3])

    # 比较查询
    book15 = models.Book.objects.filter(id__gt=3)  # id大于3,great
    book15 = models.Book.objects.filter(id__lt=3)  # id小于3 less
    book15 = models.Book.objects.filter(id__gte=3)  # id大于等于3 equal
    book15 = models.Book.objects.filter(id__lte=3)  # id小于等于3 equal

    # 日期查询
    # 查询1980年出版的图书
    book16 = models.Book.objects.filter(pub_data__year=1980)
    # 查询1980年1月1日后发布的图书
    book17 = models.Book.objects.filter(pub_data__gt=date(1981, 1, 1))

    ###################################
    # Q对象,表示查询条件之间的逻辑关系,与&,或 | 非~(波浪号),
    # 查询id大于3并且价格大于100的书
    book18 = models.Book.objects.filter(id__gt=3, price__gt=100)
    book19 = models.Book.objects.filter(Q(id__gt=3) & Q(price__gt=90))
    # 这是第二种写法
    # 查询id大于3或价格大于100的书
    book19 = models.Book.objects.filter(Q(id__gt=3) | Q(price__gt=90))
    # 查询id不等于1的书籍
    book20 = models.Book.objects.filter(~Q(id=1))

    # F对象,用于类属性之间的比较,
    # 查询图书的价格大于库存数量的书籍
    book21 = models.Book.objects.filter(price__gt=F('inventory_num'))
    # 查询价格大于2倍库存数量的图书信息
    book22 = models.Book.objects.filter(price__gt=F('inventory_num') * 2)

#####################
    # 查询集
    # 使用all,filter,exclude,orderby,调用这些函数会产生一个查询集,querySet类对象可以使用继续调用上面的所有函数
    # 惰性查询,就是说你不展示数据的时候,是不查询数据库的,
    book1 = models.Book.objects.all()  # 返回一个查询集,这一句还没有查询数据库,最后return的时候才才去查数据库
    # 缓存,就是说你第一次查过了,就会进入缓存,下次不会再次查询一次了,
    # 对查询集可以进行切片,切换之后就和原来的查询集没有关系了,
    book2 = models.Book.objects.all()
    book2 = book2[0:2]

    return HttpResponse(book23)

 

 ###############    django-多表查询    ################

if __name__ == "__main__":
    import os,django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
    django.setup()
    from app01 import models

    # 模型类关系
    # 表之间有三种关系,
    # 一对多,出版社和作者,ForeignKey,注意:这种关系必须写在多的表中,
    # 多对多,作者和书籍,ManyToManyField,这种定义在哪一个表都可以,
    # 一对一,作者和作者详情,OneToOneField,这种定义哪一个表都可以,

    # 外键的跨表查询
    # 正向查找,这是查询书籍id为1的出版社的名字
    #       基于对象:
    # book1 = models.Book.objects.first()
    # publiseh1 = book1.publisher.name
    #       基于下划线的:
    book2 = models.Book.objects.filter(id=1).values("publisher__name")
    # 反向查找
    #   基于对象
    publisher_obj = models.Publisher.objects.get(id=1)
    # book3=publisher_obj.book_set.all()
    # 如果在外键中设置了related_name = books
    book3 = publisher_obj.books.all()
    #   基于下划线的,
    # models.Publisher.objects.filter(id=1).values('book__title')
    # 如果在外键中设置了related_name = books
    book4 = models.Publisher.objects.filter(id=1).values("books__title")

    # 逆向查询, 需要加上表名__字段名
    # 查询图书信息,要求图书信息关联的作者中包含:曹
    book5 = models.Book.objects.filter(author__name__contains='曹')
    # 正向查询,需要是字段名__对应表的字段名
    # 查询书名为三国志的作者,
    author6 = models.Author.objects.filter(book__id=1)

    #########################
    # 多对多操作
    # 作者和书籍就是多对多的,

    # 通过作者创建一本书籍
    author_obj = models.Author.objects.first()
    from datetime import date
    # author_obj.book.create(title='鬼吹灯',publisher_id=1,price=123,inventory_num=123,sales_num=123,pub_data=date(1999,1,1))
    # book_obj = models.Book.objects.first()
    # author_obj.book.add(book_obj) #这是添加一个,
    book_obj=models.Book.objects.filter(id__gt=4)
    # author_obj.book.add(*book_obj)
    # author_obj.book.add(8)
    # set()更新model对象的关联对象
    # author_obj.book.remove(book_obj)
    # author_obj.book.clear()
    # 额外补充,外键的反向操作,
    # 找到id=1的出版社,
    # publisher_obj = models.Publisher.objects.get(id=1)
    # publisher_obj.books.clear()  # 这个只是把书关联的出版社字段清空了,这本书还在,
    # 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。print(ret3)

 

 ###############    django--聚合和分组    ################

if __name__ == "__main__":
    import os,django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
    django.setup()
    from app01 import models

    from django.db.models import Count,Sum

    # 聚合函数;
    # 查询所有书的数目
    book23 = models.Book.objects.all().aggregate(Count('id'))  # 这是返回一个字典
    book23 = book23.values()
    book23 = models.Book.objects.all().count()  # 这是返回一个数字,不是字典,
    # 书籍销量总和
    book24 = models.Book.objects.all().aggregate(Sum('inventory_num')).values()  # 返回也是一个字典
    # 最大和最小就是一样的使用方法
    # ret=models.Book.objects.all().aggregate(price_avg=Avg('price'),price_max=Max('price'),price_min=Min('price'),price_sum=Sum('price'))
    # print(ret.get('price_max')) #可以通过这种方式把值取出来,

    # 分组

    # 逻辑:
    # 根据书分组,
    # 然后配合聚合函数,求作者的数量
    # 然后数量就是一个属性,就可以拿出来了,
    ret1 = models.Book.objects.all().annotate(author_num=Count('author'))  # count里面是表名,
    # ret1是把所有的书查询出来了,但是里面的具体的书是多了一个属性就是author_num,
    for book in ret1:
        print(book.author_num)
        print(type(book))
    # 对结果还可以进行过滤,
    ret2 = models.Book.objects.all().annotate(author_num=Count('author')).filter(author_num__gt=1)

    # 查询出各个作者出版的书的总价格
    # 逻辑:
    # 1,查询所有的作者,
    # 2,根据每一个作者分组,加上一个总价price_sum,这个时候每一个字段就是一个属性,
    # 3,然后取出price_sum
    # 所以连接了三张表,,
    ret3 = models.Author.objects.all().annotate(price_sum=Sum('book__price')).values_list( 'name', 'price_sum')


    print(ret3)

  

###############    django--ORM进行增删改查操作    ################

if __name__ == "__main__":
    import os,django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
    django.setup()
    from app01 import models

    # 使用ORM进行增删改查操作,
    # 查询:
    ret = models.Publisher.objects.all()
    # 创建:
    # models.Publisher.objects.create(name='五棵松',addr='望京')
    # 删除:
    # models.Publisher.objects.get(id=4).delete()
    # 修改:
    ret2 = models.Publisher.objects.first()
    ret2.name=ret2.name+'123'
    ret2.save()  # 修改的时候一定要有这个

    # 一对多的修改,
    # 前端传入id,new_book_title,new_publisher_id
    # edit_id=1
    # new_book_title='水浒传'
    # new_publisher_id=1
    # edit_book_obj = models.Book.objects.get(id=edit_id)
    # edit_book_obj.title = new_book_title
    # edit_book_obj.publisher_id = new_publisher_id
    # edit_book_obj.save()  # 保存

    # 多对多的修改,
    edit_id=6
    new_author='南派三叔'
    new_publisher_id=1
    new_books=(1,2)
    edit_author_obj = models.Author.objects.get(id=edit_id)
    edit_author_obj.name = new_author
    edit_author_obj.book.set(new_books)  # 这种表关联的方式是符合更新值的,这个要记住,new_books是书的id,可以是多个值,
    edit_author_obj.save()


    print(ret)

 

 ###############    django--orm多对多的三种方式    ################

if __name__ == "__main__":
    import os,django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
    django.setup()
    from app01 import models
    
    # orm多对多的三种方式
    
    
    #多对多的方式
    # 1,orm自动帮我创建第三张表,书和作者之间的第三张表就是自动创建的,
    # 2,自己创建第三张表,利用外键分别关联作者和书,查询比较麻烦
    # 3,自己创建第三张表,使用orm的manyTomanyField,制定一下,
    # book=models.ManyToManyField(to='book',through='Author2Book',through_fields=("author","book"))
    #第三种的查询方式和第一种的查询方式一样的,因为已经做了关联了,
    
    
    # 我们使用第几种,
    #如果第三张表没有额外的字段,就使用第一种方法,
    #如果第三张表有额外的字段,这种可以使用第三种方法和第一种方法,
    # 比如相亲网站,一个男的可以联系多个女的,一个女的也可以联系多个男的,这就是多对多的,
    #约会记录,多对多,这个表的结构,
    #id boy_id girl_id date 约会时间,
    # 注意:
    #第三种方式,这种add() remove() 就没有了,
    # 举例:
    # 从作者关联的书里面移除id是1的书
    # 之前使用第一种方法的时候是:
    # models.Author.objects.get(id=1).book.remove(1)
    # 现在自己建第三张表,就不能使用这种方式了,
    # models.Author2Book.objects.get(author_id=1,book_id=1).delete()
    
    #在app01里面查询id=1的作者关联的书,
    # author_obj=models.Author.objects.get(id=4)
    # ret=author_obj.book.all()
    # print(ret)
    
    #在app02里面查询id=1的作者关联的书,
    # author_obj=models.Author.objects.get(id=4)
    # ret=author_obj.book.all()
    # print(ret)
    #如果是你自己创建的第三张表,就不能使用这种方法了,因为里面没有book这个属性啊,
    #怎么拿?
    #先拿到作者为1的数据,在关联表
    ret=models.Author2Book.objects.filter(author_id=4).values_list('book_id')
    print(ret)#<QuerySet [(4,), (5,)]>
    ret=[i[0] for i in ret] #看来列表推导式还是需要研究一下
    ret=models.Book.objects.filter(id__in=ret)
    print(ret)
    #所以这种自己建立第三张表是比较麻烦的,
    

 

 ###############    django--事务,原子操作    ################

if __name__ == "__main__":
    import os,django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
    django.setup()
    from app01 import models
    import datetime

    # 事务,原子操作,
    try:
        from django.db import transaction #导入一个transaction
        with transaction.atomic():  #atomic原子,下面的语句要么都成功,要么都不成功,这样就可以了,这就是事务,
            new_publisher = models.Publisher.objects.create(name="火星出版社")
            models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
    except Exception as e:
        print(str(e))
上一篇:excel记录20191213


下一篇:第12章学习笔记(20191213兰毅达)