• python之路(19)django数据库模型(model)


    前言

      object relation mapping(ORM)关系对象映射表,一个类实例映射为一条表记录

    目录


     数据库配置

            1.django 默认使用sqlite的数据库,如果需要使用mysql数据库,就需要在settings中修改配置信息 

           

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME' : '',  #你的数据库的名字
            'USER' : '', #你的数据库用户
            'PASSWORD' : '', #你的数据库密码
            'HOST' : '', #你的数据库主机,默认localhost
            'PORT' : '3306', #你的数据库端口
        }
    }
    mysql数据库配置信息

            2.需要手动导入PyMySQL,在_init_.py中导入

    import MySQLdb
    #注:如果想要显示表执行的sql语句,就在settings中配置
    
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }

    创建类

    1. 在models.py中创建类映射表

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.FloatField()
        pub_date=models.DateField()
        publish = models.ForeignKey("Publish", on_delete=models.CASCADE) #一对多
        authors = models.ManyToManyField("Author") #多对多
    
        def __str__(self):
            return self.name
    
    
    class Publish(models.Model):
    
        name=models.CharField(max_length=32)
        city=models.CharField(max_length=32)
    
        def __str__(self):
            return self.name
    
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField(default=20)
    
        def __str__(self):
            return self.name

     2.在终端中输入 python manage.py makemigrations , python manage.py migrate 两条命令

    类属性进阶操作

    class UserInfo(models.Model):
        
        age = CharFiled(是否为空,类型,长度,列名,索引,错误提示,自定义验证规则)
        ...
        ...
    字段参数
    
        null                        数据库中字段是否可以为空
        db_column                   数据库中字段的列名
        default                     数据库中字段的默认值
        primary_key                 数据库中字段是否为主键
        db_index                    数据库中字段是否可以建立索引
        unique                      数据库中字段是否可以建立唯一索引(用于一对一)
        unique_for_date             数据库中字段【日期】部分是否可以建立唯一索引
        unique_for_month            数据库中字段【月】部分是否可以建立唯一索引
        unique_for_year             数据库中字段【年】部分是否可以建立唯一索引
        
        verbose_name                Admin中显示的字段名称
        blank                       Admin中是否允许用户输入为空
        editable                    Admin中是否可以编辑
        help_text                   Admin中该字段的提示信息
        choices                     Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                                    如:gf = models.IntegerField(choices=[(0, 'chen'),(1, 'xiaoyi'),],default=1)
        
        error_messages              自定义错误信息
                                    字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                                    如:{'null': "不能为空.", 'invalid': '格式错误'}

     单表操作

    -----------# 单表
        #添加方法一
        b = Book(name="python基础",price=99,author="chen",pub_date="2017-12-12")
        b.save()
    
        #添加方法二
        Book.objects.create(name="PHP基础",price=70,author="chen",pub_date="2016-12-12")
    
    -----------# 单表
        Book.objects.filter(author="liu").delete()
        
    -----------# 单表
        Book.objects.filter(author="chen").update(price=100)
        
     -----------# 单表
        book_list = Book.objects.all()
        print(book_list[0])
    
        book_list = Book.objects.all()[::-2]
        book_list = Book.objects.all()[::2]
        book_list = Book.objects.first()
        book_list = Book.objects.last()
        book_list = Book.objects.get(id=4) #只能取出一条记录的时候不报错
        ret = Book.objects.filter(author="chen").values("name","price") #以字典的形式显示
        ret = Book.objects.filter(author="chen").values_list("name","price") #以元组的形式显示
        book_list = Book.objects.exclude(author="chen").values("name","price") #除了chen以外的人的数据
        book_list = Book.objects.all().values("name").distinct() #根据一个字段去重
        ret = Book.objects.all().values("name").distinct().count() #根据一个字段去重
        Book.objects.filter(authors__id__in=[1,2]) #获取id等于1或2的数据
        Book.objects.filter(authors__id__range=[1,2]) #范围
    
    
        #万能的__
        #价格大于50的数/85.41
        book_list = Book.objects.filter(price__gt=50).values("name","price")
    
        #模糊查询
        book_list = Book.objects.filter(name__icontains="P").values("name","price")

    一对多(外键)

    外键关系及参数

    ForeignKey(ForeignObject)
    
        to,                         要进行关联的表名
        to_field=None,              要关联的表中的字段名称
        on_delete=None,             当删除关联表中的数据时,当前表与其关联的行的行为
                                    - models.CASCADE,删除关联数据,与之关联也删除(常用)
                                    - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
                                    - models.PROTECT,删除关联数据,引发错误ProtectedError
                                    - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                                    - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
        related_name = None,        反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      在Admin或ModelForm中显示关联数据时,提供的条件:
                                        如:
                                                - limit_choices_to={'nid__gt': 5}
                                                - limit_choices_to=lambda : {'nid__gt': 5}
    
        db_constraint=True          是否在数据库中创建外键约束
        parent_link=False           在Admin中是否显示关联数据

    书籍和出版社是一对多的关系

    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.FloatField()
        pub_date=models.DateField()
        publish = models.ForeignKey("Publish", on_delete=models.CASCADE) #一对多
    
        def __str__(self):
            return self.name
    
    
    class Publish(models.Model):
    
        name=models.CharField(max_length=32)
        city=models.CharField(max_length=32)
    
        def __str__(self):
            return self.name

    添加数据的方法

    #多表添加
        Book.objects.create(name="linux运维",price=77,pub_date="2017-12-12",publish_id=2)
    
    
        Book.objects.create(name="GO",price=23,pub_date="2017-05-12",publish=publish_obj)

    多表查询的方法

    #含外键:一对多查询
        # 查询人民出版社出过的所有书籍名字和价格
        # 方式一:
        pub_obj=Publish.objects.filter(name="人民出版社")[0]
        ret=Book.objects.filter(publish=pub_obj).values("name","price")
    
    
        #方式二
        pub_obj = Publish.objects.filter(name="人民出版社")[0]
        print(pub_obj.book_set.all().values("name","price")) #book_set
        print(type(pub_obj.book_set.all()))
    
        # 方式三,用__
        ret=Book.objects.filter(publish__name="人民出版社").values("name","price")
    
    
    #python基础书出版社的名字
        #法一
        ret = Publish.objects.filter(book__name="Python基础").values("name")
    
        # 法二
        ret3=Book.objects.filter(name="python基础").values("publish__name")
    
     #北京出版出版的所有的书
        ret = Book.objects.filter(publish__city="北京").values("name")
        ret = Publish.objects.filter(city="北京")

     一对一(外键+unique)

    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.FloatField()
        pub_date=models.DateField()
        publish = models.ForeignKey(
            to = "Publish", 
            on_delete=models.CASCADE,
            unique=True,
            ) #一对一
    
        def __str__(self):
            return self.name
    
    
    class Publish(models.Model):
    
        name=models.CharField(max_length=32)
        city=models.CharField(max_length=32)
    
        def __str__(self):
            return self.name

    多对多(关系表)

    多对多关系及参数 

    ManyToManyField(RelatedField)
        to,                             要进行关联的表名
        related_name=None,              反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,        反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,          在Admin或ModelForm中显示关联数据时,提供的条件:
                                            如:
                                                - limit_choices_to={'nid__gt': 5}
                                                - limit_choices_to=lambda : {'nid__gt': 5}
        symmetrical=None,               仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                            #可选字段有:code, id, m1
                                                class BB(models.Model):
    
                                                code = models.CharField(max_length=12)
                                                m1 = models.ManyToManyField('self',symmetrical=True)
    
                                            # 可选字段有: bb, code, id, m1
                                                class BB(models.Model):
    
                                                code = models.CharField(max_length=12)
                                                m1 = models.ManyToManyField('self',symmetrical=False)
                                                
        through = None,                 自定义第三张表时,使用字段用于指定关系表
        through_fields = None,          自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                            from django.db import models
    
    
                                            class Person(models.Model):
                                                name = models.CharField(max_length=50)
    
    
                                            class Group(models.Model):
                                                name = models.CharField(max_length=128)
                                                members = models.ManyToManyField(
                                                    Person,
                                                    through='Membership',
                                                    through_fields=('group', 'person'),
                                                )
    
    
                                            class Membership(models.Model):
                                                group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                                person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                                inviter = models.ForeignKey(
                                                    Person,
                                                    on_delete=models.CASCADE,
                                                    related_name="membership_invites",
                                                )
                                                invite_reason = models.CharField(max_length=64)
    
        db_constraint = True,           是否在数据库中创建外键约束
        db_table = None,                默认创建第三张表时,数据库中表的名称

    书籍和作者是多对多的关系

    注:使用authors = models.ManyToManyField("Author"),会自动创建book_authors表,也可以自己创建关系表(不会有authors属性)
    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.FloatField()
        pub_date=models.DateField()
        authors = models.ManyToManyField("Author") #多对多
    
        def __str__(self):
            return self.name
    
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField(default=20)
    
        def __str__(self):
            return self.name

     -----------#绑定多表关系
        book_obj = Book.objects.get(id=4)
        authors_objs = Author.objects.get(id=2) #authors_objs = Author.objects.all()
        book_obj.authors.add(authors_objs)
        
     -----------#多对多的关系,第三张表关系表
        #通过对象的方式绑定关系
        #书找作者
        book_obj=Book.objects.get(id=3)
        print(book_obj.authors.all())
    
    
    #作者找书
        author_obj = Author.objects.get(id=2)
        print(author_obj.book_set.all())
        return HttpResponse("添加成功")
        
     -----------# 解除多表关系
        book_obj = Book.objects.get(id=4)
        authors_objs = Author.objects.all() #是列表
        book_obj.authors.remove(*authors_objs)
        book_obj.authors.remove(2)  #删除的是数量
    
    #清空
        book_obj.authors.clear()
        
     -----------#修改的set()方法
        book_obj = Book.objects.get(id=4)
        book_obj.authors.set([2,3])

    手动创建的多表关系

    #手动创建关系表
    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.FloatField()
        pub_date=models.DateField()
    
        def __str__(self):
            return self.name
    
    
     class Book_Author(models.Model):
         book=models.ForeignKey("Book",on_delete=models.CASCADE)
         author=models.ForeignKey("Author",on_delete=models.CASCADE)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField(default=20)
    
        def __str__(self):
            return self.name
    -----------#手动创建的关系表
      Book_Author.objects.create(book_id=2,author_id=3)
    
    -----------#关联查询,查找书的所有作者
      obj = Book.objects.get(id=2)
      print(obj.book_author_set.all()[0].author)
    
    #chen出过的书和价格
      ret = Book.objects.filter(book_author__author__name="chen").values("name","price")

    手动创建的表因为没有第三张的字段,因此没有自动创建的表查询的方便,而自动创建的表默认只有三个字段

    因此引入   手动+自动联合创建表

    class User(models.Model):
        username = models.CharField(max_length=32,db_index=True)
    
        def __str__(self):
            return self.username
    
    class Tag(models.Model):
        title = models.CharField(max_length=16)
    
        m = models.ManyToManyField(
            to='User',
            through='UserToTag',
            through_fields=['u','t']
        )
    
        def __str__(self):
            return self.title
        #使用ManyToManyField只能在第三张表中创建三列数据
    
    class UserToTag(models.Model):
        # nid = models.AutoField(primary_key=True)
        u = models.ForeignKey(to='User')
        t = models.ForeignKey(to='Tag')
        ctime = models.DateField()
        
        #用于关系表u,t两个字段共同约束唯一
        class Meta:
            unique_together=[
                ('u','t'),
            ]

    自关联

    用户粉丝互相关注(在同一张用户表里,用户互相关联)

    class User(models.Model):
        username = models.CharField(max_length=32,db_index=True)
    
        d = models.ManyToManyField('User',related_name='b')
        def __str__(self):
            return self.username
    注:自关联的跨表查询
    symmetrical=None, 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 #可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False)

    聚合函数,Q函数,F函数

    先导入模块

    from django.db.models import Min,Avg,Max,Sum
    from django.db.models import F,Q
    #聚合函数(需要先导入函数)
         ret = Book.objects.all().aggregate(Avg("price"))
         ret = Book.objects.all().aggregate(chen_money = Sum("price")) #取别名
    
    
    #查各个作者的书的价格总和
        value:按照作者名字分组
        ret = Book.objects.values("authors__name").annotate(Sum("price"))
        print(ret)
    
    #查各个出版社出的书的最小
        ret = Publish.objects.values("name").annotate(Min("book__price"))
        print(ret)
    
    
    #-----------------------------------------------------------------------------------------------------------------------------
    
    #F查询和Q查询,(使用前要导入模块)
    #F拿到的值
      Book.objects.all().update(price=F("price")+10)
    
    #Q可以做or操作 ,~Q表示非
      re = Book.objects.filter(Q(price=80) | Q(name="GO"))
    #组合查询
      re = Book.objects.filter(Q(name__contains="G"))
    
    
    #Q查询和关键字查询组合,Q要在前面
      re = Book.objects.filter(Q(name="GO"),price=80)
     

    惰性取值,迭代对象,exists()函数

    #只有在使用ret使用的时候才去查询,惰性取值
      re = Book.objects.filter(price=80) #不会取值
    
      for i in re: #使用时才会去查询
         print(i)
      
      print(re)
    
    #---------------------------------------------------------------------
    
    #exists()
      re = Book.objects.filter(price=80)
      re.exists() #会查询,但re不会被赋值,只有使用re变量的时候才会被赋值
    
    #----------------------------------------------------------------------
    
    #iterator() 迭代器对象
      ret = Book.objects.filter(price=80)
      ret = ret.iterator()
  • 相关阅读:
    Java8IntStream数值流的常用操作以及与装箱和拆箱的关系
    iOS滚动回弹修复方案
    ios Safari 不兼容问题 transform rotateY
    typescript的?? 和?: 和?.是什么意思?还有!:
    原生js解决ios手机input输入框弹出覆盖问题
    requestIdleCallback和requestAnimationFrame的区别
    axios的兼容性问题
    第三方直播SDK对比(腾讯云,阿里云,网易云信,七牛云,金山云,声网,即构科技)
    直播平台对比
    react中实现路由缓存和组件缓存
  • 原文地址:https://www.cnblogs.com/shuzhixia/p/11062437.html
Copyright © 2020-2023  润新知