美文网首页
Django_02数据操作

Django_02数据操作

作者: tzktzk1 | 来源:发表于2023-11-27 20:46 被阅读0次

    数据操作--ORM模型

    保存数据的途径---数据库
    操作数据库的方法----

    1.原生sql
    2.ORM模型

    ORM的概念

    Object Relational Mapping(对象关系映射)

    其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。 ... 当然这只是从对象到SQL的映射,还有从SQL到对象的映射,也是类似的过程。
    有了ORM,我们不需要再写繁琐的sql语句,一切以python语法为准,通过ORM提供的API就可以操作数据库

    主流的数据库都被Django 官方支持:

    • PostgreSQL
    • MariaDB
    • MySQL
    • Oracle
    • SQLite

    模型定义

    以Event(发布会)为例,继承django自带的model类,并定义相应的字段
    每个字段类都对应一种数据库字段格式

    • 名称
      字符串 最大长度256 非空
    • 开始时间
      datetime格式时间
    • 地址
      字符串 最大长度256 非空
    • 人数
      整数
    • 状态
      布尔 默认 true
    • 创建时间
      datetime格式时间

    常用的数据库字段类型(ORM)

    CharField

    最常用的类型,字符串类型。必须接收一个max_length参数,表示字符串长度不能超过该值。

    BooleanField

    布尔值类型。默认值是None

    DateTimeField

    日期时间类型。Python的datetime.datetime的实例。

    IntegerField

    整数类型,范围-2147483648 到 2147483647的值在 Django 支持的所有数据库中都是安全的。

    附录:字段类型参考:https://docs.djangoproject.com/zh-hans/3.1/ref/models/fields/#field-types

    常用字段选项(ORM)

    null

    如果是 True, Django 将在数据库中存储空值为 NULL。默认为 False。

    default

    该字段的默认值。可以是一个值或者是个可调用的对象,不能是一个可更改的对象(模型实例、list、set 等)。

    unique

    如果设置为 True,这个字段必须在整个表中保持值唯一。默认为False。若为True该字段可以成为一个唯一索引

    verbose_name

    字段的一个人类可读名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。

    剩余通用字段参考:https://docs.djangoproject.com/zh-hans/3.1/ref/models/fields/#field-options

    模型字段定义代码参考:models.py

            from django.db import models
            
            # Create your models here.
            
            # 发布会模型--需要继承django自带的模型基类
            class Event(models.Model):
                # 名称--字符串 最大长度256
                name = models.CharField(max_length=256,null=False)
                # 地点
                address = models.CharField(max_length=256)
                # 人数
                limits = models.IntegerField(default=100)
                # 状态
                status = models.BooleanField(default=True)
                # 开始时间--允许为空
                start_time = models.DateTimeField(null=True)
    
    字段命名约束:

    Django不允许下面两种字段名:

    1.与Python关键字冲突。这会导致语法错误。
    2.字段名中不能有两个以上下划线在一起,因为两个下划线是Django的查询语法。
    3.字段名不能以下划线结尾,原因同上。

    由于你可以自定义表名、列名,上面的规则可能被绕开,但是请养成良好的习惯,一定不要那么起名。

    模型方法

    可以修改模型自带的str方法,这样在查询的时候,就能看到对应的数据信息了

            from django.db import models
            
            # Create your models here.
            
            # 发布会模型--需要继承django自带的模型基类
            class Event(models.Model):
                # 名称--字符串 最大长度256
                name = models.CharField(max_length=256,null=False)
                # 地点
                address = models.CharField(max_length=256)
                # 人数
                limits = models.IntegerField(default=100)
                # 状态
                status = models.BooleanField(default=True)
                # 开始时间--允许为空
                start_time = models.DateTimeField(null=True)
            
                # 覆盖对象对外的字符串表现形式
                def __str__(self):
                    return self.name
    

    对比:修改前

      >>> from sgin.models import Event
      >>> Event.objects.all()
      <QuerySet [<Event: Event object (1)>]>
    

    对比:修改后:

      >>> from sgin.models import Event
      >>> Event.objects.all()
      <QuerySet [<Event: 测开发布会>]>
    

    激活模型与数据迁移

    激活模型

    settings.py中添加应用名称以关联app

      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'demo', #注册app,
          'sgin'
      ]
    

    配置数据库信息

    默认使用的是sqlite,不需要配置,若要改成其他数据库,可以参考以下配置修改:如改成mysql

      # settings.py
      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',    #数据库引擎
              'NAME': 'sqtp',                          #数据库名称
              'USER': 'root',                          #用户名
              'PASSWORD': 'devops',                    #密码
              'HOST': '192.168.21.140',                #数据库IP
              'PORT': '3306',                          #数据库端口
         }
      }
    

    附录:数据库配置 https://docs.djangoproject.com/zh-hans/3.1/intro/tutorial02/

    模型迁移3步曲

    • 1编辑 models.py 文件,改变模型。

    • 2运行 python manage.py makemigrations 为模型的改变生成迁移文件,类似以下输出。

      (venv) D:\Course\course_django\djangosite>python manage.py makemigrations
      Migrations for 'sgin':
       sgin\migrations\0003_auto_20231128_1848.py
         - Alter field phone on guest
      
    • 3运行 python manage.py migrate 来应用数据库迁移 ,类似以下输出

      (venv) D:\Course\course_django\djangosite>python manage.py migrate
      Operations to perform:
       Apply all migrations: admin, auth, contenttypes, sessions, sgin
      Running migrations:
       Applying sgin.0002_guest... OK
       Applying sgin.0003_auto_20231128_1848... OK
      
    迁移的内部过程

    makemigrations命令---做语法预检查,生成操作数据库的命令,并不操作数据库,此时发生的错误都和数据库无关
    migrate命令 将前一步的命令落实到数据库,此时发生的错误都和数据库有关

    数据的增删改查API

    调用模型API--- 通过模型的管理器
    语法:模型类.objects.方法

    增加

    Model.objects.create(**kws)

    修改

    数据对象.字段=值
    数据对象.save() #调用save才会保存到数据库
    (千万不要用 Model.objects.update(**kws) 会把所有数据记录都更改)

    删除

    数据对象.delete()

    查询---最丰富的操作

    Model.objets.all() ---- 获取所有查询结果,返回QuerySet对象
    Model.objets.filter(**kw) --- 条件过滤查询,返回QuerySet对象,不加参数效果和all()一样
    Modle.objets.get() --- 获取单个数据对象 #没有匹配结果或者匹配结果超过1个都会报错查询是web中最频繁也是最丰富的操作

    ORM执行查询参考:https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/

    测试API--体验Django自带的命令行

    python manage.py shell

    Django自带的后台数据管理

    用API手动创建的方式还是太麻烦,后续我们可以用API编写到接口里面
    现在,我们先用Django自带的后台来管理数据

    1. 模型注册到admin.py

       # admin.py
       from django.contrib import admin
       from .models import Event
       # Register your models here.
       admin.site.register(Event)
      
    2. 创建管理员用户 python manage.py createsuperuser

    3. 新增数据

    创建数据--发布会

    功能迭代--修改视图

    修改event视图

    从数据库读取数据

    event_list = Event.objects.all()

    修改发布会详情视图 event_detail

    修改视图event_detail
    #发布会详情页
    def event_detail(request,_id):
        # 从某处获取到当前页面的发布会数据对象
        event = Event.objects.get(id=_id)
        return render(request,'event_detail.html',{'event':event})
    

    发布会详情页url可以设计成 event_detail/<int:event_id>
    django会把event_detail/2类型的url 解析成 event_detail/<int:event_id >
    event_id 可作为event_detail视图函数的参数,注意参数名需要相同
    此为django解析foo/path/数字 类型的url的规则 若变化的值为字符串,将int改为str即可

    修改url,增加ID
    path('sgin/event_detail/<int:event_id>',views.event_detail),
    
    修改发布会详情页 event_detail.html
    {% extends 'base.html' %}
    {% block title%}发布会详情页{% endblock %}
    {% block content%}
      <div class="panel panel-info">
        <div class="panel-heading"> 发布会详情页 </div>
        <div class="panel-body">
          <p>发布会名称:{{ event.name }}</p>
          <p>发布会时间:{{ event.start_time }}</p>
          <p>发布会地址:{{ event.address }}</p>
          <p><a href="/sgin/events" class="btn btn-info">返回发布会列表</a></p>
        </div>
      </div>
    {% endblock %}
    
    修改列表页的URL,events.html
    {% extends "base.html" %}
    {% block title%}发布会管理{% endblock %}
    {% block content%}
      <ul class="list-group">
        {% for event in event_list %}
          <li class="list-group-item text-center">
          <a href="/sgin/events/{{ event.id }}">{{ event }}</a>
          </li>
        {% endfor %}
      </ul>
    {% endblock %}
    

    需求2实现嘉宾列表和详情页

    1.创建嘉宾数据模型对象
    至少包括手机号,姓名,邮箱,和关联的发布会
    2.模仿发布会列表和详情页,创建嘉宾视图路由以及模板页面
    /sgin/guests/ #嘉宾列表
    /sgin/guest_details/int:id #嘉宾详情页
    现在的视图逻辑关系

    image.png

    按照需求,嘉宾需要与发布会进行关联,这个就涉及到了数据库表关联的关系。

    数据库表关联

    后端系统开发中, 数据库设计是重中之重。
    特别是前后端分离的系统, 后端的职责基本就是数据管理, 开发的代码几乎都是围绕数据操作的。
    虽然,这里不是专门讲数据库的, 但也必须讲解常用的 数据库表 和 表之间的关系 的设计 。

    目前 使用的数据库系统 主要还是 关系型数据库 。
    什么是关系型数据库?就是建立在关系模型基础上的数据库。
    大家耳熟能详的mysql、oracle、 sqlserver、SQLite 都是,而 mongodb、Cassandra不是
    而关系型数据库,设计的一个难点就是 各种表之间的关联关系 。
    常见的3种关联关系就是: 一对多 , 一对一 , 多对多

    例子
    1对多: 1个老师可以上多门课程,对应多门课程

    models.ForeignKey # 定义在多方

    多对多:1个学生可以对应多门课程,1门课程也可以对应多个学生

    models.ManyToManyField #定义在任意1方,只能定义在1方,不能双方都定义

    多对1:1个男盆友对应1个女盆友...

    models.OneToOneField # 定义在多方

    嘉宾的与发布会的关系可先定为多对1

    模型定义代码参考

      # 定义发布会关联嘉宾
      class Guest(models.Model):
          # django会自动帮你创建一个id字段作为主键
          # 关联发布会
          event = models.ForeignKey(Event,on_delete=models.CASCADE)  #CASCADE 如果删除了
      关联的发布会,该嘉宾也会被删除
          # 姓名 字符串 64 唯一
          name = models.CharField(max_length=64,unique=True)
          # 手机号 字符串 11   唯一
          phone = models.CharField(max_length=11,unique=True)
          # 邮箱 邮箱格式 xxx@yyy.zz
          email = models.EmailField()
          # 加入时间 --创建数据的时候就自动取当前时间 auto_now_add=True
          join_time = models.DateTimeField(auto_now_add=True)
          def __str__(self):
              return self.name
    

    不要忘记运行命令同步到数据库。同时更新url和view.

    urls.py

      # 嘉宾列表
          path('guests/',views.guests),
          # 嘉宾详情
          # 将guest_id/2类型的url 解析成guest_detail/<int:guest_id>
          # guest_id 可作为guest_detail视图函数的参数,注意参数名需要相同
          path('guest_detail/<int:guest_id>',views.guest_detail),
    

    views.py

    # 嘉宾列表
    def guests(request):
        # 从数据库获取所有嘉宾
        guest_list = Guest.objects.filter()
        # 返回页面并填充数据
        return render(request,'guests.html',{'guest_list':guest_list})
    # 嘉宾详情
    def guest_detail(request,guest_id):
        # 根据获取的ID取对应的嘉宾
        guest = Guest.objects.get(pk=guest_id)
        # 返回页面并且填充嘉宾
        return render(request,'guest_detail.html',{'guest':guest})
    

    最后:网页模板

    guests.html

    {% extends 'base.html' %}
    {% block content %}
        <ul class="list-group">
           {% for guest in guest_list %}
                <li class="list-group-item text-center"><a href="/sgin/guest_detail/{{ guest.id }}">{{ guest.name }}</a></li>
           {% endfor %}
        </ul>
    {% endblock %}
    

    guest_detail.html

    {% extends 'base.html' %}
    {% block content %}
        <div class="panel-info panel">
            <div class="panel-heading"> 嘉宾详情页 </div>
            <div class="panel-body">
            <p>参与发布会:{{ guest.event }}</p>
            <p>姓名:{{ guest.name }}</p>
            <p>手机号:{{ guest.phone }}</p>
            <p>邮箱:{{ guest.email }}</p>
            <p>加入时间:{{ guest.join_time }}</p>
            <p><a href="/sgin/guests" class="btn btn-info">返回列表</a></p>
        </div>
        </div>
    {% endblock %}
    

    附录

    模型字段参考:https://docs.djangoproject.com/zh-hans/3.1/ref/models/fields/#field-types
    数据库配置:https://docs.djangoproject.com/zh-hans/3.1/intro/tutorial02/
    数据库访问优化:https://docs.djangoproject.com/zh-hans/3.1/topics/db/optimization/
    字段命名限制:https://docs.djangoproject.com/zh-hans/3.1/topics/db/models/#field-name-restrictions
    模型方法:https://docs.djangoproject.com/zh-hans/3.1/topics/db/models/#model-methods
    模型管理器:https://docs.djangoproject.com/zh-hans/3.1/topics/db/managers/
    ORM执行查询:https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/
    QuerySetAPI参考:https://docs.djangoproject.com/zh-hans/3.1/ref/models/querysets/

    相关文章

      网友评论

          本文标题:Django_02数据操作

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