Django-ORM

Posted 123why

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django-ORM相关的知识,希望对你有一定的参考价值。

# 在Django中默认使用自带的sqlite数据库
# 如果想使用mysql,在settings.py文件中添加下面语句,把之前的sqlite配置注掉
    DATABASES = {
        default: {
            ENGINE: django.db.backends.mysql, 
            NAME: books,    #你的数据库名称
            USER: root,   #你的数据库用户名
            PASSWORD: ‘‘, #你的数据库密码
            HOST: ‘‘, #你的数据库主机,留空默认为localhost
            PORT: 3306, #你的数据库端口
        }
    }

TIME_ZONE = Asia/Shanghai   # 使用上海时间

# 这时候创建数据库会报错,因为Django默认使用MySQLdb,这是python2的模块,在python3中使用pymysql
# 要解决这个问题,在项目的__init__.py文件中添加
import pymysql
pymysql.install_as_MySQLdb()

# 创建表=========================================
# models.py
from django.db import models

from django.contrib.auth.models import User # django自带的用户登录验证
#使用时在用户表中添加user字段Foreignkey(User)

#创建一张表,可以不写主键id ,创建表时会自动创建
class Book(models.Model):      # 必须继承这个库
    name = models.CharField(
        null=True                      # 字段可以为空
        max_length=25,                # 必填
        db_column = user# 数据库列名name->user
        db_index = True,                # 创建索引
        unique = True,                    # 加速查找,限制列值唯一
        primary = True,                  # 加速查找,限制列值唯一且非空
        #admin属性
        verbose_name=user,
        blank=True,                        # 在admin中字段是否可以为空
        editable=True ,                   # 在admin中是否可编辑
        help_text= 帮助信息,
        choices                                 # 下拉框选项
        # gf = models.IntegerField(choices=[(0,"v1"),(1,"v2"),],default=1)
        error_messages
        validators                           #自定义错误验证
        
        )
    price = models.IntegerField()
    pub_date = models.DateField()
    class Meta:
        uninque_together("字段一","字段二")    # 联合唯一
        abstract = True     # abstract:抽象的 使定义的这个modle不生成表,只用来供其他model类继承



    想要创建表就在命令行输入下面两条命令
    python manage.py makemigrations
    python manage.py migrate
    
#添加表记录
#方法一---------------------------------------------------
#一个实例对象就是一条表记录,先创建一个对象,再保存
b = Book(name = "python",price=45,........)
b.save()

#方法二---------------------------------------------
Book.objects.create(name = "python",price=45,........)



#修改表记录
# 方式一------------------------------------------
Book.objects.filter().update()                        # <class ‘django.db.models.query.QuerySet‘>  
# 方式二-------------------------------------------
b.Book.objects.get()                                             # <class ‘app01.models.Book‘>
b.prince = 80
b.save()

# 删除表记录
Book.objects.filter().delete()

# 查询表记录 
1.  all()      # 取出全部,支持切片
2.  first() # 取出第一个
3.  last()   # 取出最后一个
4.  get()   #一定会取出那一条记录的对象,其他的是取出一组对象,哪怕只有一个
5.  values    values_list   #通过filter筛选出来的多条记录,可以通过调用这两个方法,获取其中的某个字段,前者是字典,后者是元组
6.  exclude()  # 取出除筛选条件之外的记录
7.  distinct()   # values取字段的时候可能会取到重复字段,用该方法可以去重
# 万能的双下划线-------------------------------
__gt#字段名下的数据小于,prince__gt = 10,prince大于10的记录  ,__gte大于等于
__contains   # 字段中包含,  name__contains = "p" ,包含"p",  __icontains不区分大小写


# 多表操作(一对多)

    #添加外键,比如把书绑定到出版社
        /*
        class ForeignKey(to,on_delete,**options) 。
        第一个参数是引用的是哪个模型,第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,
        比如有 CASCADE 、 SET_NULL 等
        */
         - 一对一
            - 一张表其实就是一对一
            -两张表的一对一要添加约束唯一性
         -一对多
            # class Userinfo(models.Model):
            #     username = models.CharField(
            #         max_length=32,
            #     )
            #     p_k = models.ForeignKey(
            #         to="Part",                       # 关联的表
            #         to_field="id",                   # 关联的字段,默认关联ID
            #         on_delete=models.CASCADE,        #与之关联的数据全部删除
                                                                                                        #- models.DO_NOTHING,引发错误IntegrityError
                                                                                                        #- models.PROTECT,   引发错误ProtectedError
                                                                                                        #- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                                                                                                        #- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
                                                                                                        #- models.SET,删除关联数据,
                                                                                                                      #a. 与之关联的值设置为指定值,设置:models.SET(值)
                                                                                                                      #b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
            #     )
            # class Part(models.Model):
            #     name = models.CharField(
            #         max_length=32,
            #     )
         -多对多
            -多对多的第三张表有两种创建方式
                a. 添加ManyToMany字段
                    mk = models.ManyToManyField(
                        to="Tag",
                        related_name=None,                 # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
                        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values(‘表名__字段名‘)
                        limit_choices_to=None,        # 在Admin或ModelForm中显示关联数据时,提供的条件:
                        db_table=None,                         # 创建第三张表时的表名
                        db_constraint=True, 
                        through=None,                           # 指定关系表,即不自动创建,而使用手动创建的第三张表,但有些方法无法使用如add
                        through_fields=None,
                    )
                 b.手动创建第三张表
                    class Utotag(models.Model):
                    u = models.ForeignKey(to="User",on_delete=models.CASCADE)
                    t = models.ForeignKey(to="Tag",on_delete=models.CASCADE)
                    class Meta:                         # 约束多对多关系,使对应的多不能重复
                        verbose_name = u图片
                        verbose_name_plural = u图片
                            unique_together = [
                                ("u","t"),          #Please correct the error below.
                            ]
         - 自关联
         # 自关联
            """
            一个网站的用户在一张表中
            用户之间的互相关注,是一种自关联
            """
            class User_list(models.Model):
                user = models.CharField(max_length=32)
                uTOu = models.ManyToManyField(to="User_list",related_name="sss")
                # 建议所有的多表关系都使用related_name
             - 会自动创建另一张表  其中的字段名 :      id       from_user_list_id        to_user_list_id  
         -select_related("外键字段")
            from app01 import models
            b_obj_list = models.B.objects.all().select_related("fk")
            for row in b_obj_list:
                print(row.name)
                print(row.fk.name)
                # for循环进行跨表查询时每次查询都会到数据库中执行查询,效率低
                #models.B.objects.all().select_related("fk"),这样关联表也会被一次取出,提升了性能
                
       # 在Book类中添加这样一个字段,public = models.ForeignKey("被关联的出版社表",on_delete=models.CASCADE)
       #django会自动在字段名后添加 _id ,默认关联到 id 上
    # 添加记录
        #方式一------------------------------------------
            Book.objects.create(name = "GO",prince=70,pub_date=2019-08-07,public_id=1)
        #方式二-------------------------------------------
            # 先获取要绑定的对象
                public_object=Public.objects.filter(name=人民出版社)[0]  # 这是一个对象集合所以取索引0
            # 之后把对象赋给外键(不加_id)
                Book.objects.create(name=python,prince=50,pub_date=2017-02-1,public=public_object)
     # 查询记录
        
        # 方式一 正向查询:根据外键找关联,先取到model,然后model.外键就取到了这个model关联的对象
                        book_model = Book.objects.get(name="python")
                        print(book_model.public.name)
                        print(book_model.public.city)
        # 方式二 反向查询:从被关联的表反向找关联表,格式:被关联表model.关联表_set.all().values() || _set.all().values_list()
                    OneToOne无法反向查询
                    pub_set = Public.objects.get(id=1)    
                    book_msg = pub_set.book_set.all().values("name","price")
                    print(book_msg)
                    #--  小写类名_set是一种默认形式,可以修改在外键参数添加related_name=""
                        cs = models.ForeignKey(Classes,on_delete=models.CASCADE,related_name="sss")
        # 正向查找和反向查找
        # ---找到学员对应班级,正向查找
        date = models.Students.objects.all().values("student_name","cs__class_name")
        # values是一个queryset字典,而values_list是元组,并且values在get和filter中不能使用
        for i in date:
            print(i["student_name"],i["cs__class_name"])

        # ---找到班级对应的学员,反向查找
        reverse_date = models.Classes.objects.get(id=2).students_set.all().values("student_name")
        print(reverse_date)
        return HttpResponse("成功")
         # 以上两种方式都是通过对象
         # 方式三:伟大的双下划线__ (可以在values中和filter中使用)

# 多表操作(多对多)
         #两张表之间的多对多需要第三张表做桥梁
         # 第一种方法是手动添加第三张表,两个外键分别关联两张表
         # 在其中一张表中添加字段 字段名 = models.ManyToManyField("另一张表名")
         
         # 之后Django会自动创建第三张表
         
         # 向第三张表中添加记录
         # 取到要关联的两个对象,使用add方法添加
             author_obj = Author.objects.get(name="alex")
             book_obj = Book.objects.get(id=2)
             book_obj.author.add(author_obj)   # .remove(),可以解除关联,也就是删除第三张表中book_obj对应的数据
             # 还可以直接传参数id号  book_obj.author.add(ID号([1,2,3]或者 2)) 
         
         # 删除数据
            book_obj.author.remove(book_obj) #可以解除关联,也就是删除第三张表中book_obj对应的数据
            book_obj.author.clear() #清空该对象的关联
         
         # 重置关联
             book_obj.author.set([1,2,3]) # 相当于清空关联,重新设置
         
         # 查询数据
             # 查找alex出过的书
                ret = Book.objects.filter(author__name="alex").values("name","price")
             # 查找GO这本书的作者
                ret1 = Book.objects.filter(name = "GO").values("author__name")
                print(ret1)
                
                    # 查询一班的老师
                            obj4=models.Classes.objects.filter(class_name="一班").first()
                            obj5=models.Classes.objects.get(class_name="一班")
                            print(obj4.ct.all().values("teacher_name"))

                            # obj=models.Classes.objects.all().values("class_name","ct__teacher_name")
                            # for i in obj:
                            #     print(i)


        # 聚合和分组
                # 聚合
                # 首先导入模块 from django.db.models import Avg Sum Min Max Count
                # 求所有书的价格
                # ret = Book.objects.aggregate(Sum("price"))
                # print(ret)
                # 分组
                # 求每个出版社出的书的价格
                ret = Public.objects.values("name").annotate(Sum("book__price"))
                print(ret)
                # 求每个作者出的书的价格
                ret2=Author.objects.values("name").annotate(Sum("book__price"))
                print(ret2)
         #F查询和Q查询
            # filter中的筛选条件可以用逗号隔开写多条,但是这些条件之间是且的关系,怎么表示或和非呢?
            # 修改一条记录,SQL语句可以直接使用算术运算符,但ORM中不行,怎么办呢
                # F查询和Q查询
                # 给每本书的价格加10
                Book.objects.all().update(price=F("price")+10)
                # 查询除了python以外的所有书
                ret = Book.objects.filter(~Q(name="python"))
                for i in ret:
                    print(i.name)
                # 查询价格是50或者60的书
                ret = Book.objects.filter(Q(price=50)|Q(price=60))
                for i in ret:
                    print(i.name)
                 ###########注意在筛选条件中F、Q和键值对可以并存,但F、Q要在键值对前面
                """
               from django.db.models import Q
                query_obj=Q()
                query_obj.connector=‘or‘
                query_obj.children.append((‘qq__contains‘,query))
                query_obj.children.append((‘name__contains‘,query))
        """
         
         # QuerySet  :查询集合的一些特点
         1.查询语句不会被立即执行,只有使用查询结果时才被执行
         2.查询的结果会放在缓存中,中间无论怎么修改,再次使用查询结果都是缓存中的,除非再次调用查询语句
         3.查询集合会全部放在内存中,当如果这个数据特别大,那么内存就会有极大的负担,所以可以吧查询集合做成一个生成器
             用的时候一条一条的取  ,给集合调用.iterator()方法

 

以上是关于Django-ORM的主要内容,如果未能解决你的问题,请参考以下文章

Django-ORM系统详述

12.Django-ORM增删改查

django-orm

Django-ORM操作

Django-orm数据库相关

Django-orm数据库查询语句