美文网首页
Django:04.ORM操作

Django:04.ORM操作

作者: Zzmi | 来源:发表于2019-05-24 17:42 被阅读0次

    一、Django连接数据库操作

    1、创建数据库 (注意设置 数据的字符编码)
    由于Django自带的orm是data_first类型的ORM,使用前必须先创建数据库
    create database ayalysis default character set utf8 collate utf8_general_ci;
    2、修改project中的settings.py文件中设置 连接 MySQL数据库(Django默认使用的是sqllite数据库)

    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'ayalysis',
        'USER': 'totd',
        'PASSWORD': 'totd890',
        'HOST': '192.168.182.128',
        'PORT': '3306',
        }
    }
    

    3、查看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',
            },
        }
    }
    

    4、修改project 中的__init__py 文件设置 Django默认连接MySQL的方式

    import pymysql
    pymysql.install_as_MySQLdb()
    

    5、setings文件注册APP

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config', 
    ]
    

    6、进行数据迁移,在winds cmd或者Linux shell的项目的manage.py目录下执行

    python manage.py makemigrations  #根据app下的migrations目录中的记录,检测当前model层代码是否发生变化?
    python manage.py migrate         #把orm代码转换成sql语句去数据库执行
    python manage.py migrate --fake    #只记录变化,不提交数据库操作
    

    二、字段类型

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

    1. 字符串类

    name=models.CharField(max_length=32)

    • EmailField(CharField):
    • IPAddressField(Field)
    • URLField(CharField)
    • SlugField(CharField)
    • UUIDField(Field)
    • FilePathField(Field)
    • FileField(Field)
    • ImageField(FileField)
    • CommaSeparatedIntegerField(CharField)

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

    MySQL知识点补充:

    char 和 varchar的区别 :
    共同点是存储数据的长度,不能 超过max_length限制;
    不同点是varchar能根据数据实际长度存储,char按指定的max_length来存储数据;所有前者更节省硬盘空间。

    2. 时间字段(详细使用
    • models.DateTimeField(null=True)
    • models.DateField()
    • models.TimeField() # 不常用
    3、数字字段

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

    • models.IntegerField() # 数字
    • models.FloatField() # 浮点
    • models.DecimalField(max_digits=8,decimal_places=3) # 精确浮点
    4、枚举字段
    choice=(
            (1, '男'),
            (2, '女'),
            (3, '其他')
        )
    gender=models.IntegerField(choices=choice)    # 枚举类型
    

    扩展:在数据库存储枚举类型,比外键有什么优势?
    1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
    2、在modle文件里不能动态增加(选项一成不变用Django的choice)

    5、其他字段
    db_index = True 表示设置索引
    unique(唯一的意思) = True 设置唯一索引
    
    联合唯一索引
    class Meta:
    unique_together = (
        ('email','ctime'),
    )
    联合索引(不做限制)
    index_together = (
        ('email','ctime'),
    )
    ManyToManyField(RelatedField)  #多对多操作
    

    三、字段参数介绍

    1. 数据库级别生效
    2. Django admin级别生效
      针对 dango_admin生效的参数(正则匹配)(使用Django admin就需要关心以下参数!!))
    • blank #是否为空
    • editable=False # 是否允许编辑
    • help_text="提示信息" # 提示信息
    • choices=choice # 提供下拉框
    • error_messages="错误信息" # 错误信息
    • validators # 自定义错误验证(列表类型),从而定制想要的验证规则(EmailValidator,URLValidator,DecimalValidator,MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator)
    from django.core.validators import RegexValidator
    from django.core.validators import EmailValidator
    
    test = models.CharField(
        max_length=32,
        error_messages={
            'c1': '优先错信息1',
            'c2': '优先错信息2',
            'c3': '优先错信息3',
        },
        validators=[
            RegexValidator(regex='root_\d+', message='错误了', code='c1'),
            RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
            EmailValidator(message='又错误了', code='c3'), ]
    

    四、单表操作

    1. ORM使用方式

    ORM操作可以使用类实例化,obj.save()的方式,也可以使用create()的形式

    2. QuerySet数据类型介绍
    • QuerySet与惰性机制:
      所谓惰性机制指Userinfo.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=models.Book.objects.all()          #惰性计算--->等于一个生成器,不应用books不会执行任何SQL操作
        # query_set缓存机制1次数据库查询结果query_set都会对应一块缓存,再次使用该query_set时,不会发生新的SQL操作;
        #这样减小了频繁操作数据库给数据库带来的压力;
        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')
    
    3. 增删改查操作

    • orm添加一条记录的方法
    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对多
        # 1、表.objects.create()
        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)
    
        # 书籍和作者是多对多关系,
        # 切记:如果两表之间存在多对多关系,例如书籍相关的所有作者对象集合,作者也关联的所有书籍对象集合
        book=models.Book.objects.get(title='西游记')
        author=models.Author.objects.get(name='吴承恩')
        author2 = models.Author.objects.get(name='张根')
        book.author.add(author,author2)
        # add()    # 添加
        # clear()    # 清空
        # remove()     # 删除某个对象
        return HttpResponse('OK')
    

    根据条件判断,增加?更新?

    # 根据user=user去查找,如果找到更新 如果没有找到创建defaults={} 中的数据
    tk = gen_tcoken(username)
    models.Token.objects.update_or_create(user=user, defaults={'token': tk})
    
    # 删除指定条件的数据
    models.Tb1.objects.filter(name='seven').delete() 
    
    def delete(request):
        # 修改方式1 update()
        ret = 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):
        # query_set对象集合 [对象1、对象2、.... ]
        books=models.Book.objects.all()
        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字典集合 [{一条记录},{一条记录} ]
        books=models.Book.objects.values(
                        'title','price',
                        'publish__name',
                        'date',
                        'classify__category',    # 正向连表: 外键字段___对应表字段
                        'author__name',    # 反向连表: 小写表名__对应表字段
                        'author__sex',    # 区别: 正向 外键字段__,反向 小写表名__
                        'author__age',
                        'author__university')
        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、通过object的形式反向连表, obj.小写表名_set.all()
    publish=models.Publish.objects.filter(name__contains='湖南').first()
    books=publish.book_set.all()
    for book in  books:
        print(book.title)
    
    # 通过object的形式反向绑定外键关系
    authorobj = models.Author.objects.filter(id=1).first()
    objects = models.Book.objects.all()
    authorobj.book_set.add(*objects)
    authorobj.save()
        
    # 2、通过values双下滑线的形式,objs.values("小写表名__字段")
    # 注意对象集合调用values(),正向查询是外键字段__XX,而反向是小写表名__YY看起来比较容易混淆;
    books=models.Publish.objects.filter(name__contains='湖南').values('name','book__title')
    authors=models.Book.objects.filter(title__icontains='我的').values('author__name')
    print(authors)
    
    # fifter()也支持__小写表名语法进行连表查询:在publish标查询 出版过《笑傲江湖》的出版社
    publishs=models.Publish.objects.filter(book__title='笑傲江湖').values('name')
    print(publishs)
    
    # 查询谁(哪位作者)出版过的书价格大于200元
    authors=models.Author.objects.filter(book__price__gt=200).values('name')
    print(authors)
    
    # 通过外键字段正向连表查询,出版自保定的书籍;
    city=models.Book.objects.filter(publish__addr__icontains='保定').values('title')
    print(city)
    

    五、ORM连表操作

    在django使用orm的时候,我们可以把一对多,多对多,分为正向和反向查找两种方式。

    • 正向查找:
      ForeignKey在 UserInfo表中,如果从UserInfo表开始向其他的表进行查询,这个就是正向操作,反之如果从UserType表去查询其他的表这个就是反向操作。
      一对多:models.ForeignKey(其他表)
      多对多:models.ManyToManyField(其他表)
      一对一:models.OneToOneField(其他表)
    • 正向连表操作总结:
      所谓正、反向连表操作的认定无非是Foreign_Key字段在哪张表决定的,Foreign_Key字段在哪张表就可以哪张表使用Foreign_Key字段连表,反之没有Foreign_Key字段就使用与其关联的 小写表名;

    1对多:对象.外键.关联表字段,values(外键字段__关联表字段)
    多对多:外键字段.all()

    • 反向连表操作总结:
      通过value、value_list、fifter 方式反向跨表:小写表名__关联表字段
      通过对象的形式反向跨表:小写表面_set().all()

    ORM跨表查询操作示例

    相关文章

      网友评论

          本文标题:Django:04.ORM操作

          本文链接:https://www.haomeiwen.com/subject/lsenzqtx.html