Django--ORM--增删改查

一、创建模型类

models.py文件中设置ORM字段。

介绍:

Django提供了很多字段类型,比如URL/Email/IP/ ,但是mysql数据没有这些类型,这类型存储到数据库上本质是字符串数据类型,其主要目的是为了封装底层SQL语句;

类型:

1、字符串类

models.CharField     对应的是MySQL的varchar数据类型

char 和 varchar的区别 :

共同点,是存储数据的长度,不能超过max_length限制;

不同点,是varchar根据数据实际长度存储,char按指定max_length()存储数据;所以,前者更节省硬盘空间;

name = models.CharField(max_length=32)

# 以下都是在数据库中,本质都是字符串数据类型,此类字段只是在Django自带的admin中生效
EmailField(CharField)         # email
IPAddressField(Field)         # IP
URLField(CharField)            # URL
SlugField(CharField)            # Slug 
UUIDField(Field)                # UUID
FilePathField(Field)            # 文件路径(/usr/local/python/)
FileField(Field)
ImageField(FileField)           # 图片路径(本质也就是图片的位置路径)
CommaSeparatedIntegerField(CharField)

2、时间字段

create_time = models.DateTimeField(null=True)   # 年月日时分秒
date = models.DateField()      # 年月日    

3、数字字段(整数、小数)

(max_digits=30,decimal_places=10)       即,总长度30,小数位10位

数字:
num = models.IntegerField()   # 整数   (也分 tiny等,即小整数,大整数,超大整数...)
num = models.FloatField()      # 浮点
price = models.DecimalField(max_digits=8, decimal_places=3)    # 精确浮点

4、枚举字段

应用场景?以及和外键对比,什么优势?

1、key-value对应,选项固定情况,即不是动态变化的。如:设备状态(使用中、未使用、故障、已下线、其他),前后端数据交互时,数据是1、2、3,只需告诉前端分别对应的是什么就可以了,因为不会改变。

2、无需连表查询性能低,省硬盘空间(选项不固定时用外键)

3、在modle文件里不能动态增加(选项一成不变,用Django的choice)

# 元祖嵌套元祖,其实可以看做是字典的生成式一种,数据表中保存的是1\2\3,key-value对应
choice=(
        (1,'男人'),
        (2,'女人'),
        (3,'其他')
    )

lover = models.IntegerField(choices=choice)        # 枚举类型

5、其他

索引

db_index = True        表示设置索引
unique = True          唯一的意思,设置唯一索引

class Meta:

    # 格式:元祖的嵌套,另外,联合索引有基本原则:最左前缀(并有序的)!!!
    unique_together = (
         ('email','ctime'),         # 联合唯一索引
    )
    
    index_together = (
        ('email','ctime'),        # 联合索引(不做限制)
    )

二、ORM操作

背景:

1、orm使用方式:

orm操作可以使用类实例化,obj.save的方式;

也可以使用create()的形式;

2、QuerySet数据类型介绍

QuerySet与惰性机制

所谓惰性机制:

Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。

QuerySet特点:

       <1>  可迭代的 

       <2>  可切片

       <3> 惰性计算和缓存机制

def queryset(request):

    books = models.Book.objects.all()[:10]  # 切片 应用分页
    books = models.Book.objects.all()[::2]
    book = models.Book.objects.all()[6]    # 索引
    print(book.title)

    for obj in books:                     # 可迭代
        print(obj.title)
    
    # 惰性计算:
    # 等于一个生成器,不应用books不会执行任何SQL操作
    # query_set缓存机制:
    # 1次数据库查询结果query_set都会对应一块缓存,再次使用该query_set时,不会发生新的SQL操作;
    # 作用:这样减小了频繁操作数据库给数据库带来的压力;
    
    books = models.Book.objects.all() 
    authors = models.Author.objects.all()
    for author in  authors:
        print(author.name)
    print('-----')
    models.Author.objects.filter(id=1).update(name='张某')
    for author in  authors:
        print(author.name)

    # 但是有时候取出来的数据量太大会撑爆缓存,可以使用迭代器优雅得解决这个问题;
    models.Publish.objects.all().iterator()
    return HttpResponse('OK')

基本操作

增加

# 准备三个表,作者(Author),书籍的分类(Classify),书籍出版(Publish)
def orm(request):

    单表
    1、方式一:表.objects.create()
    models.Publish.objects.create(name='浙江出版社', addr="浙江.杭州")
    models.Classify.objects.create(category='武侠')
    models.Author.objects.create(name='金庸',sex='男', age=89, university='东吴大学')

    2、方式二:类实例化,obj = 类(属性=XX) obj.save()
    obj = models.Author(name='吴承恩', age=518, sex='男', university='龙溪学院')
    obj.save()
    
    一对多
    1、方式一:表.objects.create(外键名_id=那个类的id)
    models.Book.objects.create(title='笑傲江湖', price=200, date=1968, classify_id=6, publish_id=6)

    2、方式二:类实例化,obj=类(属性=X, 外键=obj)  obj.save()
    classify_obj = models.Classify.objects.get(category='武侠')
    publish_obj = models.Publish.objects.get(name='河北出版社')
    # 注意以上获取得是和 book对象 向关联的(外键)的对象
    book_obj = models.Book(title='西游记', price=234, date=1556, classify=classify_obj, publish=publish_obj)
    book_obj.save()
    
    多对多
    如果两表之间存在双向1对N关系,就无法使用外键来描述其关系了;
    只能使用多对多的方式,新增第三张表关系描述表;
    book = models.Book.objects.get(title='笑傲江湖')
    author1 = models.Author.objects.get(name='金庸')
    author2 = models.Author.objects.get(name='张根')
    book.author.add(author1, author2)

    # 书籍和作者是多对多关系,
    # 如果两表之间存在多对多关系,例如书籍相关的所有作者对象集合,作者也关联的所有书籍对象集合

    # add()   添加
    # clear() 清空
    # remove() 删除某个对象
    return HttpResponse('OK')

删除

 

修改

    # 方式1:update()
    models.Book.objects.filter(id=1).update(price=3)

    # 方式2:obj.save() 
    book_obj = models.Book.objects.get(id=1)
    book_obj.price=5
    book_obj.save()

查找

def ormquery(request):

    books = models.Book.objects.filter(id__gt=2, price__lt=100) 
    book = models.Book.objects.get(title__endswith='金')   # 单个对象,没有找到会报错

    book1 = models.Book.objects.filter(title__endswith='金').first()
    book2 = models.Book.objects.filter(title__icontains='瓶').last()

    # 一般:query_set 是对象集合 [对象1、对象2、.... ]
    books = models.Book.objects.all()

    # values:query_set 是字典集合 [{一条记录},{一条记录} ]
    books = models.Book.objects.values(
        'title','price', 
        'publish__name',
        'date',
        'classify__category',         # 正向连表: 外键字段__对应表字段
        'author__name',               # 反向连表: 小写表名__对应表字段
        'author__sex',                # 区别:正向 外键字段__,反向 小写表名__
    )

    books = models.Book.objects.values('title','publish__name').distinct()  
    # exclude 按条件排除。。。
    # distinct()去重, 
    # exits()查看数据是否存在? 返回 true 和false
    a = models.Book.objects.filter(title__icontains='金').  
    return HttpResponse('OK')

一对多,多对多

1、一对多(ForeignKey)

使用时,通常定义在多的一方

# 背景:老师(一)、学生(多,外键字段名:teacher = modles.ForeignKey(Teacher,...))

# obj对象处理:id为1的老师,有哪些学生?
teacher = Teacher.objects.get(id = 1)      # 先获取对象

# 查
# 方式一:
Student类中,外键字段有定义 related_name=’teacher_student’, 可以直接用
studentList = teacher.teacher_student.all() 

# 方式二:
外键定义没写 related_name=’student_teacher’, 可以改写成:
studentList = teacher.student_set.all()     # 反向

# 增
# 方式一:create方式
teacher.student_set.create(name="tom", age=14)

# 方式二:obj通过使用add
student_obj = Student(name="tom", age=14)
teacher.student_set.add(student_obj)

# 删
student_obj = teacher.student_set.get(name="tom")
student_obj.delete()

2、多对多(ManyToManyField)

特点:

1、迁移时,会自动生成一个中间表(表示俩个表的对应关系)

2、增删改查,同时也适用一对多,一对一,修改少量参数即可

from django.db import models

class Goods(models.Model):      # 商品
    g_name = models.CharField(max_length=20)
    g_price = models.DecimalField(max_digits=5, decimal_places=2)
    gc = models.ForeignKey("Category", null=True, on_delete=models.SET_NULL)  # gc为外键,一对多,类别表为母表

class Category(models.Model):     # 类别
    c_name = models.CharField(max_length=20)

class Store(models.Model):       # 商家
    s_name = models.CharField(max_length=30)
    s_detail = models.TextField(blank=True, null=True)
    sc = models.ManyToManyField("Category")           # 与类别表进行多对多关联

查看

# 专业术语来讲,多对多关系,多对多字段设置在那个表,那个表就是子表
# 查找指定商家下面的所有分类
# 方式一:正向查询
Store.objects.get(s_name="商家C").sc.all()     # 写法:子表对象.子表多对多字段.过滤条件 
(all()/filter())
<QuerySet [<Category: Category object>, <Category: Category object>]>

# 方式二:反向查询
Category.objects.filter(store__s_name="商家C")
Out[25]: <QuerySet [<Category: Category object>, <Category: Category object>]>  # 母表对象.filter(子表表名小写__子表字段名="过滤条件")

# 从分类查询,查看那些商家里面发布指定的某一个分类
# 方式一:
(Category.objects.get(c_name="电脑整机")).store_set.all()  # 写法:母表对象.子表表名小写_set.过滤条件
<QuerySet [<Store: Store object>, <Store: Store object>]>

# 方式二:
Store.objects.filter(sc=Category.objects.get(c_name="电脑整机"))
<QuerySet [<Store: Store object>, <Store: Store object>]>

# 方式三:
Store.objects.filter(sc__c_name="电脑整机")   # filter(子表外键字段__母表字段='过滤条件')
<QuerySet [<Store: Store object>, <Store: Store object>]>

# 方式四:
Store.objects.filter(sc=category)  # filter得到QuerySet,写法:filter(子表外键字段=母表主键对象),此处和一对多略有不同,是子表外键字段而不是外键字段_母表主键
<QuerySet [<Store: Store object>, <Store: Store object>]>

 

增加

# 普通添加(一对一)
# 添加商家
# 方式一:
Store.objects.create(s_name="商家A", s_detail="物美价廉,抄底折扣。。。。")
Out[2]: <Store: Store object>

# 方式二:
Store(s_name="商家B", s_detail="大促销").save()

# 添加类别
Category.objects.create(c_name="电脑整机")
<Category: Category object>

Category(c_name="文具耗材").save()

# ---------------------------------------------------
# 总结:增与改(增添子表或母表数据参照一对一的增,多对多重点在于关系表的对应关系变更 - 中间表的对应关系)
# ---------------------------------------------------

# 多对多

# 创建商家C并添加全部分类(多对多添加时,add 追加对象,而Category.objects.all()是对象集合)
方式一:
Store.objects.create(s_name="商家C").sc.add(*(Category.objects.all()))  # 如果商户已存在则把create改成get

方式二:
store = Store.objects.get(s_name="商家C")
store.sc = (Category.objects.all())
store.save()

# ---------------------------------------------------

# 创建商家D添加指定分类
# 方式一:
store = Store.objects.create(s_name="商家D")
category = Category.objects.filter(c_name__in=["电脑整机","文具耗材"])  # 单个改成get,全部改成all
store.sc.add(*category)     # add是追加模式,category是一个查询集(对象集合)
# store.sc.clear()            # 清空此商家的商品(其实就是清除了,中间表的对应关系)

# 方式二:
# 让指定商品分类添加指定的商家,反向查询
store = Store.objects.create(s_name="商家E")
category = Category.objects.get(c_name="电脑整机")
category.store_set.add(store)       
# 效果与上面一样

# ---------------------------------------------------

# 让所有商家都添加这个分类
stores = Store.objects.all()
category = Category.objects.get(c_name="电脑整机")
category.store_set.add(*stores)

category.store_set.clear()       # 让所有商家去除这个分类,删除的是这个类
category.store_set.all().delete()       # 是删除这个类的所有商家,删除的是商家

# ---------------------------------------------------
# 总结
# 只有子表才有"子表名小写_set"的写法,得到的是一个QuerySet集合(对象集合),后边可以接.add(),.remove(),.update(),.delete(),.clear()

删除

# 问题一:让指定商家清空分类     (即,这个商家和所有分类表没有关系了,面向的是商家)
s = Store.objects.get(s_name="商家C")
s.sc = ""
s.save()

s=Store.objects.get(s_name="商家C")
c = Category.objects.all()    # 对象集合
s.sc.remove(*c)

s = Store.objects.get(s_name="商家C")
s.sc.clear()

# 删除母表与子表关联关系

# 问题二:让所有商家去掉指定分类   (即,这个指定分类和所有商家表没有关系了,面向的是指定分类)
s = Store.objects.all()
c = Category.objects.get(c_name="电脑整机")
c.store_set.remove(*s)

c = Category.objects.get(c_name="电脑整机")
c.store_set.clear()

# 删除商家该子表数据
# 删除所有指定分类的全部商家

c = Category.objects.get(c_name="电脑整机")
c.store_set.all().delete()

# 删除所有商家  (对比下,区别理解)
Store.objects.all().delete()

 

bug坑点

我在多对多字段中,定义了related_name字段,导致role__id__in=role_ids,反向查询使用“小写表名__字段名”失效,报错:无法解析role字段,即根本没能找到Role的这个关联表。

 

 

参考文件

多对多处理,首选看看:https://blog.csdn.net/maidou931019/article/details/74852536

多层级--跨表关系查询,首选看看:https://blog.csdn.net/pushiqiang/article/details/81127442

 

很全面和详细的,非常不错的一篇:https://blog.csdn.net/qq_26870933/article/details/81563149

 

大牛神器

借鉴链接:

模型基础--field--方法--ORM:https://code.ziqiangxuetang.com/django/django-models.html

自定义field:https://code.ziqiangxuetang.com/django/django-custom-field.html

 

ORM

参考链接:

https://code.ziqiangxuetang.com/django/django-queryset-api.html

https://code.ziqiangxuetang.com/django/django-queryset-advance.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值