Django与数据库

news2024/9/21 10:58:12

目录

创建项目app

 路由子表

数据库

 创建数据库

什么是ORM

定义数据库表

Django Admin 管理数据

过滤条件

代码直接生成HTML

 使用模板

前后端分离架构

对资源的增删改查处理

列出客户

 添加客户

 临时取消 CSRF 校验

修改客户信息

 删除客户

Django中ORM的处理

数据模型的配置

字段设置

字段参数

数据更新的实现

 


创建项目app

Django中的一个app就是项目里面的一个应用的意思,一个项目包含多个app,一个app通常就是一个相对独立的模块,实现相对独立的功能。比如我们可以把系统中的管理员管理的功能放在一个名为mgr的app里面,把销售人员的操作实现在另一个名为sales的app里面。

Django中创建app可以通过执行命令,创建一个app目录,并在里面自动创建app常用的文件。

进入项目根目录,执行以下命令:

python manage.py startapp sales

这样就会创建一个目录名为 sales, 对应 一个名为 sales 的app,里面包含了如下自动生成的文件: 

migrations
__init__.py
admin.py
apps.py
models.py
tests.py
views.py

 路由子表

一个请求对应一个处理函数,项目较大时,请求的url会特别多,我们可以将不同的路由记录按照功能分拆到不同的url路由子表中。

数据库

后端开发基本需要操作数据,包括数据的存储、查询、修改、删除。通常,这些都是通过数据来完成,目前业界最广泛使用的数据库还是:关系型数据库

关系型数据库系统,常用的开源数据库有mysql和postgresql.

 创建数据库

项目中数据库的配置在settings.py中。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # 数据库类型
        'NAME': 'core',  # 所使⽤的数据库的名字
        'USER': 'root',  # 数据库服务器的⽤户
        'PASSWORD': 'xxxxxx',  # 密码
        'HOST': '127.0.0.1',  # 主机
        'PORT': '3306',  # 端⼝
    }
}

执行以下命令,创建数据库:

python manage.py migrate

 项目的根目录下面生成一个配置文件中指定的数据库文件:db.sqlite3。

并且会在其中创建一些表。

什么是ORM

Django里面,数据库的操作,包括数据的增删改查,基本都是通过Model类型的对象进行的。

通常,在Django中:

  • 定义一张数据库表就是定义一个继承自django.db.models.Model的类
  • 定义该表中的字段(列),就是定义该类里面的一些属性
  • 类的方法就是对该表中数据的处理方法,包括数据的增删改查

这样,开发者对数据库的访问,从原来的使用底层的sql语句,变成面向对象的开发,通过一系列对象的类定义和方法调用就可以操作数据库。

这样做:

首先极大地简化了我们应用中的数据库开发,因为无需使用sql语句操作数据库了,提高了开发的效率。

其次屏蔽了不同的数据库访问的底层细节,开发好代码后,如果要换数据库,几乎不需要改代码,修改几个配置项即可。

这种通过对象操作数据库的方法被称为ORM(object relational mapping)。

Django的ORM(对象关系映射)是一个强大的工具,用于在Django应用程序中管理数据库,借助它我们可以使用Python代码而不是编写SQL语句来操作数据库,这是因为Django的ORM提供了一个高级的抽象层,通过定义Python类来表示数据库表,并使用这些类来执行常见的数据库操作,如创建、读取、更新和删除数据。

定义数据库表

我们再创建一个名为common的应用目录,里面存放我们项目需要的一些公共的表的定义。

执行以下命令:

python manage.py startapp common

创建了一个名为common的app.

打开common/models.py,发现里面是空的,因为我们还没有定义我们的业务所需要的表。

加入以下内容:

from django.db import models


class Customer(models.Model):
    name = models.CharField(max_length=100)
    phonenumber = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

 这个Customer类继承自django.db.models.Model,就是用来定义数据库表的,里面的name,phonenumber,address是该表的3个字段。

CharField对象对应的是varchar类型的数据库字段。定义表中的字段就是定义一些静态属性,这些属性是django.db.models里面的各种Field对象,对应不同类型的字段。

在settings.py中加入一句代码:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sales',
    # 加入以下代码:
    'common.apps.CommonConfig'
]

 'common.apps.CommonConfig' 告诉 Django,CommonConfig 是 common/apps.py 文件中定义的一个应用配置的类。

class CommonConfig(AppConfig):
    name = 'common'

CommonConfig 是 AppConfig的 子类, 就表示这个是应用的配置类。

这里 name = 'common' , name 是用来定义 应用的python模块路径的。也就是说 应用 模块路径为 common 。

 Django知道了我们的common应用,可以在项目根目录下执行命令

python manage.py makemigrations common

得到以下结果:

Migrations for 'common':
  common\migrations\0001_initial.py
    - Create model Customer

会发现在 common\migrations 目录下面出现了0001_initial.py, 这个脚本就是相应要进行的数据库操作代码。

随即,执行如下命令:

python manage.py migrate

查看数据库,发现创建了一张名为 common_customer的表。

多出来的 id 字段是该表的主键, 是Django自动帮我们添加的。

这个不需要我们在类中显式的定义。

注意:

如果以后我们修改了Models.py 里面的库表的定义,都需要再次运行 python manage.py makemigrations common 和 python manage.py migrate 命令,使数据库同步该修改结果

Django Admin 管理数据

Django提供了一个管理员操作界面,可以方便地添加、修改、删除定义的model表数据。

首先,我们需要创建一个超级管理员账号,进入到项目的根目录,执行以下命令,依次输入要创建的管理员的登录名、email、密码。

python manage.py createsuperuser
Username (leave blank to use '21544'): present
Error: That username is already taken.
Username (leave blank to use '21544'): present-01
Email address: 0123@qq.com
Password: 
Password (again): 
Superuser created successfully.

然后需要修改应用里面的管理员配置文件common/admin.py,注册我们定义的model类,这样Django才会知道

from django.contrib import admin

from .models import Customer
admin.site.register(Customer)

 然后可以访问 http://127.0.0.1/admin/ ,输入刚才注册的用户密码登录。

登录后可以看到如下界面。这里面是目前系统中可以修改的表。

点击ADD,添加用户之后点击SAVE,使用数据库查看工具,就发现数据库中确实有了添加的数据信息:

 我们先实现一个函数,来处理sales/customers/访问请求,返回数据库中customer表所有记录。

Django中对数据库表的操作,建议都是通过其对应Model对象的方法来进行的,而不是SQL语句。

比如我们要获取customer表所有记录,该表是和我们前面定义的Customer类管理的,我们可以这样获取所有表的记录:

在文件sales/views.py中,定义一个listcustomers函数,内容如下:

# 导入 Customer 对象定义
from  common.models import  Customer

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    # 每条表记录都是是一个dict对象,
    # key 是字段名,value 是 字段值
    qs = Customer.objects.values()

    # 定义返回字符串
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '

        # <br> 表示换行
        retStr += '<br>'

    return HttpResponse(retStr)

Customer.objects.values() 会返回一个 QuerySet 对象,这个对象是Django 定义的,在这里它包含所有的Customer 表记录,QuerySet对象可以使用for循环遍历取出里面所有的元素,每个元素对应一条表记录。每条表记录元素都是一个dict对象,其中每个元素的key是表字段名,value是该记录的字段值。上面的代码可以将每条记录的信息存储到字符串中,返回给前端浏览器。

还需要修改路由表,加上对sales/customers/ url请求的路由。

在bysms/urls.py主路由文件中,已有以下记录:

    # 凡是 url 以 sales/  开头的,
    # 都根据 sales.urls 里面的 子路由表进行路由
    path('sales/', include('sales.urls')),

 我们只需修改 sales/urls.py 即可,添加如下记录:

    path('customers/', views.listcustomers),

然后可以在浏览器输入如下 网址: http://127.0.0.1/sales/customers/

回车后,浏览器显示结果类似如下:

 和我们数据库中的记录信息一致:

过滤条件

有的我们需要根据过滤条件查询部分客户信息。

比如,当用户在浏览器输入 /sales/customers/?phonenumber=13000000001 ,要求返回电话号码为 13000000001 客户记录。

我们可以通过 filter 方法加入过滤条件,修改view里面的代码,如下所示:

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 定义返回字符串
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '
        # <br> 表示换行
        retStr += '<br>'

    return HttpResponse(retStr)

Django框架在url路由匹配到函数后,调用函数时,会传入一个HttpRequest对象给参数变量request,该对象里面包含了请求的数据信息。

HTTP的GET请求url里面的参数(术语叫querystring里面的参数),可以通过HttpRequest对象的GET属性获取,这是一个类似dict的对象。

比如要获取querystring里面的phonenumber参数,就可以像这样:

ph =  request.GET.get('phonenumber',None)

第二个参数传入None表示,如果没有phonenumber参数在querystring中,就会返回None

然后调用QuerySet对象的filter方法,就可以把查询过滤条件加上去

qs = qs.filter(phonenumber=ph)

有了这个过滤条件,Django 会在底层执行数据库查询的SQL语句 加上相应的 where 从句,进行过滤查询。注意,参数名 phonenumber 是和 定义的表 model 的属性名 phonenumber 一致的。

filter的过滤条件可以有多个,只要继续在后面的参数添加过滤条件即可。

代码直接生成HTML

HTML本身其实也是字符串,只是这个字符串里面的内容是符合HTML语言规范的。

既然它也是字符串,我们可以使用Python直接构建出 HTML 字符串内容。

修改:

# 先定义好HTML模板
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>

        %s


        </table>
    </body>
</html>
'''

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 生成html模板中要插入的html片段内容
    tableContent = ''
    for customer in  qs:
        tableContent += '<tr>'

        for name,value in customer.items():
            tableContent += f'<td>{value}</td>'

        tableContent += '</tr>'

    return HttpResponse(html_template%tableContent)

我们用一个变量 html_template 存储html模板,代码中生成html 里面需要插入的表格记录的内容,这个内容是html片段,也就是 html 表格的每行 。

最后填入到 html_template 模板里面,就产生了完整的HTML 字符串。

最后返回该 html 文档 字符串 即可。

修改后,再次访问 http://127.0.0.1/sales/customers/

得到如下内容:

 

 使用模板

上面我们是用Python代码直接拼接出html内容。

但是这种方式处理代码比较麻烦。特别是当html里面有多处内容需要填入时,使用Python代码直接拼接就显得很繁杂,不好维护。

很多后端框架都提供了一种 模板技术, 可以在html 中嵌入编程语言代码片段, 用模板引擎(就是一个专门处理HTML模板的库)来动态的生成HTML代码。

我们修改一下代码,使用Django的模板引擎:

# 先定义好HTML模板
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>

        {% for customer in customers %}
            <tr>

            {% for name, value in customer.items %}            
                <td>{{ value }}</td>            
            {% endfor %}

            </tr>
        {% endfor %}

        </table>
    </body>
</html>
'''

from django.template import engines
django_engine = engines['django']
template = django_engine.from_string(html_template)

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 传入渲染模板需要的参数
    rendered = template.render({'customers':qs})

    return HttpResponse(rendered)

然后,访问浏览器,可以得到一样的结果。

对比 Python直接产生 HTML,可以发现使用模板引擎的好处,就是产生HTML的代码更简单方便了。

因为我们可以直接把要生成的 HTML片段 写在 HTML模板 里面。

然后,只需要传入渲染模板所需要的参数就可以了,模板引擎会自动化帮我们生成HTML

前后端分离架构

 界面完全交给前端开发人员去做, 后端开发只需要提供前端界面所需要的数据即可。

前端和后端之间的交互就完全是业务处理了,需要定义好前端和后端交互数据的接口

目前通常这样的接口设计最普遍的就是使用REST风格的API接口。

前端通过API接口从后端获取数据展示在界面上,也通过API接口告诉后端需要更新的数据是什么。

通常前后端的API接口是由架构师设计的,有时也可以由经验丰富的前端开发者或者后端开发者设计。

对资源的增删改查处理

前面我们已经为 销售员用户 专门创建了一个应用 sales 来处理相关的 请求,我们可以 再为 管理员用户 专门创建一个应用 mgr 来处理相关的 请求。

执行以下命令:

python manage.py startapp mgr

我们可以发现对资源的增删改查 操作, 都是同一个URL,都是 /api/mgr/customers 。

而且我们发现,不同的操作请求,使用不同的 HTTP 请求方法 ,比如 添加是POST, 查询是 GET, 修改是 PUT, 删除是 DELETE

而且请求的参数中都有 action 参数表明这次请求的操作具体是什么。

注意:Django 的 url路由功能 不支持 根据 HTTP 请求的方法 和请求体里面的参数 进行路由

就是不能像下面这样,来根据请求 是 post 还是 get 来 路由:

path('customers/', 'app.views.list_customer', method='get'),
path('customers/', 'app.views.add_customer',  method='post'),

有一种方式是:自己编写一个函数, 来 根据 http请求的类型 和请求体里面的参数 分发(或者说路由)给 不同的函数进行处理。

我们可以 在 customer.py 中定义如下 dispatcher 函数:

def dispatcher(request):
    # 将请求参数统一放入request 的 params 属性中,方便后续处理

    # GET请求 参数在url中,同过request 对象的 GET属性获取
    if request.method == 'GET':
        request.params = request.GET

    # POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
    elif request.method in ['POST','PUT','DELETE']:
        # 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
        request.params = json.loads(request.body)


    # 根据不同的action分派给不同的函数进行处理
    action = request.params['action']
    if action == 'list_customer':
        return listcustomers(request)
    elif action == 'add_customer':
        return addcustomer(request)
    elif action == 'modify_customer':
        return modifycustomer(request)
    elif action == 'del_customer':
        return deletecustomer(request)

    else:
        return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})

该函数 把 请求消息中的参数统一放入到 request请求对象的params 属性中。

params 属性 被 做成一个 dict 类型 , 方便后面的处理函数来获取消息中的参数。

然后 dispatch函数再根据 请求的 类型 和 action 参数的值 决定由那个函数具体处理该请求消息。

比如 action 参数 为 'add_customer' 的 请求 就由 addcustomer 函数 进行处理。

当然在文件的开头,我们需要 先导入 JsonResponse 和 json 的定义,像下面这样:

from django.http import JsonResponse
import json

接下来,根据 API 接口 ,我们发现 凡是 API 请求url为 /api/mgr/customers 的,都属于 客户 相关的API, 都应该交由 我们上面定义的dispatch函数进行分派处理。

那么我们需要在Django的url路由文件中加入对应的路由

第一步:我们应该在 总路由文件 bysms/urls.py 中定义了如下部分:

    # 凡是 url 以 api/mgr  开头的,
    # 都根据 mgr.urls 里面的 子路由表进行路由
    path('api/mgr/', include('mgr.urls')),

 第二步: 在 mgr 目录下面添加 urls.py 路由文件, 并 加入如下声明即可, 如下所示:

from django.urls import path

from mgr import customer

urlpatterns = [

    path('customers', customer.dispatcher),
]

这样,就表示 凡是 API 请求url为 /api/mgr/customers 的,都交由 我们上面定义的dispatch函数进行分派处理 。

列出客户

根据接口文档,列出客户数据接口,后端返回的数据格式如下:

{
    "ret": 0,
    "retlist": [
        {
            "address": "江苏省常州武进市白云街44号",
            "id": 1,
            "name": "武进市 袁腾飞",
            "phonenumber": "13886666666"
        },

        {
            "address": "北京海淀区",
            "id": 4,
            "name": "北京海淀区代理 蔡国庆",
            "phonenumber": "13990123456"
        }
    ]              
}

这里我们无需 将数据库中获取的数据 转化为 供浏览器展示的HTML。

在前后端分离的开发架构中,如何展示数据是前端的事情。后端只需要根据接口文档, 返回原始数据即可。

我们可以使用如下的函数来返回数据库的所有的 客户数据信息

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 将 QuerySet 对象 转化为 list 类型
    # 否则不能 被 转化为 JSON 字符串
    retlist = list(qs)

    return JsonResponse({'ret': 0, 'retlist': retlist})

当然在文件的开头,我们需要 先导入 Customer 定义,像下面这样:

# 导入 Customer 
from common.models import Customer
 添加客户

根据接口文档,添加客户数据接口,前端提供的客户数据格式如:

{
    "action":"add_customer",
    "data":{
        "name":"武汉市桥西医院",
        "phonenumber":"13345679934",
        "address":"武汉市桥西医院北路"
    }
}

我们可以使用如下的函数来处理:

def addcustomer(request):

    info    = request.params['data']

    # 从请求消息中 获取要添加客户的信息
    # 并且插入到数据库中
    # 返回值 就是对应插入记录的对象 
    record = Customer.objects.create(name=info['name'] ,
                            phonenumber=info['phonenumber'] ,
                            address=info['address'])


    return JsonResponse({'ret': 0, 'id':record.id})

Customer.objects.create 方法就可以添加一条Customer表里面的记录。 

 临时取消 CSRF 校验

根据接口文档,添加客户 请求是个Post请求

POST /网站名/api/mgr/signin  HTTP/1.1
Content-Type:   application/x-www-form-urlencoded

注意,新创建的项目, Django 缺省会启用一个 CSRF (跨站请求伪造) 安全防护机制。

在这种情况下, 所有的Post、PUT 类型的 请求都必须在HTTP请求头中携带用于校验的数据。

为了简单起见,我们先临时取消掉CSRF的 校验机制,等以后有需要再打开。

要临时取消掉CSRF的 校验机制,非常简单,只需要在 项目的配置文件 bysms/settings.py 中 MIDDLEWARE 配置项 里 注释掉 'django.middleware.csrf.CsrfViewMiddleware' 即可。

如下所示:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
修改客户信息

 根据接口文档,修改客户数据接口,前端提供的数据格式如下:

{
    "action":"modify_customer",
    "id": 6,
    "newdata":{
        "name":"武汉市桥北医院",
        "phonenumber":"13345678888",
        "address":"武汉市桥北医院北路"
    }
}

我们可以使用如下的函数来处理:

def modifycustomer(request):

    # 从请求消息中 获取修改客户的信息
    # 找到该客户,并且进行修改操作

    customerid = request.params['id']
    newdata    = request.params['newdata']

    try:
        # 根据 id 从数据库中找到相应的客户记录
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id 为`{customerid}`的客户不存在'
        }


    if 'name' in  newdata:
        customer.name = newdata['name']
    if 'phonenumber' in  newdata:
        customer.phonenumber = newdata['phonenumber']
    if 'address' in  newdata:
        customer.address = newdata['address']

    # 注意,一定要执行save才能将修改信息保存到数据库
    customer.save()

    return JsonResponse({'ret': 0})
 删除客户

根据接口文档,删除客户数据接口,前端只需要提供要删除的客户的ID。

数据格式如下:

{
    "action":"del_customer",
    "id": 6
}

我们可以使用如下的函数来处理:

def deletecustomer(request):

    customerid = request.params['id']

    try:
        # 根据 id 从数据库中找到相应的客户记录
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id 为`{customerid}`的客户不存在'
        }

    # delete 方法就将该记录从数据库中删除了
    customer.delete()

    return JsonResponse({'ret': 0})

Django中ORM的处理

模型(Models):核心组件,一个模型类代表了一个数据库表,而类的属性则对应着表的字段

字段(Fields):模型类的属性通常被称为字段,各种字段类型在定义模型类中的属性和数据库表中的字段

查询集(QuerySets):数据库查询的方法,允许以链式方式构建复杂的查询,过滤、排序和限制结果集等操作

关联(Relations):定义模型之间的关联关系,关系使得进行数据查询和操作变得更加容易

迁移(Migrations):用于管理数据库模式的变化,更改模型定义时,可以使用迁移工具自动更新数据库表结构,而无需手动编写SQL语句

数据模型的配置

字段设置

AutoField:自增

IntegerField:整数字段,用于存储整数值

FloatField:浮点字段,存储小叔数值

CharField:字符字段,用于存储字符串

TextField:文本字段,用于存储长文本

字段参数

max_length:针对字符串或者长文本指定字段的最大长度

default:指定字段的默认值

null:设置字段是否允许为null

db_column:设置列的别名

on_delete:在外键设置中指定在关联的对象被删除时的处理方式

models.py中的代码:

from django.db import models


# Create your models here.
# 学校信息
class School(models.Model):
    id = models.AutoField('记录编号', primary_key=True)  # 主键
    name = models.CharField('学校名称', max_length=32, null=False)
    address = models.CharField('学校地址', max_length=200)

    class Meta:
        db_table = 'father_school'  # 表名


# 校长信息
class Principal(models.Model):
    id = models.AutoField('记录编号', primary_key=True)  # 主键
    name = models.CharField('校长名称', max_length=20, null=False)
    school = models.OneToOneField(School, on_delete=models.CASCADE, db_column="school_id")

    class Meta:
        db_table = 'father_principal'  # 表名


# 院系信息
class Department(models.Model):
    id = models.AutoField('记录编号', primary_key=True)  # 主键
    name = models.CharField('院系名称', max_length=32, null=False)
    school = models.ForeignKey(School, on_delete=models.CASCADE, db_column="school_id")

    class Meta:
        db_table = 'father_department'  # 表名


# 授课教师
class Teacher(models.Model):
    id = models.AutoField('记录编号', primary_key=True)  # 主键
    name = models.CharField('教师名称', max_length=20, null=False)
    Department = models.ForeignKey(Department, on_delete=models.CASCADE, db_column="department_id")

    class Meta:
        db_table = 'father_teacher'  # 表名


# 学生信息
class Student(models.Model):
    id = models.AutoField('记录编号', primary_key=True)  # 主键
    name = models.CharField('学生名称', max_length=20, null=False)
    gender = models.CharField('学生性别', default='男', max_length=2, null=False)
    age = models.IntegerField('学生年龄', default=18, null=False)
    school = models.ForeignKey(School, on_delete=models.CASCADE, db_column="school_id")
    Teacher = models.ManyToManyField(Department, db_column="student_id")

    class Meta:
        db_table = 'father_student'  # 表名

数据更新的实现

添加信息:

insert into 表名(列名列表) values(值列表)

修改信息:

update 表名 set 列名=值... where 修改条件

删除信息:

delete from 表名 where 修改条件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1982938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QThread::wait: Thread tried to wait on itself

调用QThread的wait()方法时&#xff0c;报警&#xff1a;QThread::wait: Thread tried to wait on itself 原因&#xff1a;在自己的线程中调用线程的wait()方法。 解决方法&#xff1a;在线程外的其他线程中&#xff0c;调用线程的wait()方法。 示例代码如下&#xff1a; …

MATLAB学习之绘图篇(二维图)

目录 1.1基础图形绘制 1.1.1使用plot函数进行图形绘制 1.1.2为图像增加图例 1.1.3为图片增加标题以及坐标轴的描述 1.1.4控制坐标轴&#xff0c;边框以及网络 1.1.5在一个图像上绘制多条曲线 1.1.6在一个窗口绘制多个图像 1.1.7对图形的对象进行操作( 坐标属性&#xff…

LeetCode Hot100 二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&#xff1a; 输入&#xf…

【C/C++】C语言和C++实现Stack(栈)对比

我们初步了解了C&#xff0c;也用C语言实现过栈&#xff0c;就我们当前所更新过的有关C学习内容以栈为例子&#xff0c;来简单对比一下C语言和C。 1.C中栈的实现 栈的C语言实现在【数据结构】栈的概念、结构和实现详解-CSDN博客 &#xff0c;下面是C实现的栈&#xff0c; 在St…

ImageNet数据集和CIFAR-10数据集

一、为什么需要大量数据集 人工智能其实就是大数据的时代&#xff0c;无论是目标检测、图像分类、还是现在植入我们生活的推荐系统&#xff0c;“喂入”神经网络的数据越多&#xff0c;则识别效果越好、分类越准确。因此开源大型数据集的研究团队为人工智能的发展做了大量贡献…

QT教程-十五,Qt-5.14.2安卓开发环境配

目录 一&#xff0c;Qt需要的组件 二&#xff0c;需要的环境配置 1,JDK配置 1.1 配置JDK环境 1.2 Qt中配置JDK,SDK,NDK 2,创建Qt安卓项目 2.1 配置gradle-5.5.1-bin.zip文件 最近想开发一款安卓app应用&#xff0c;但是又不想去重新学习一个新的知识体系。于是在自己更为…

2024.8.5 作业

1> 使用有名管道实现&#xff0c;一个进程用于给另一个进程发消息&#xff0c;另一个进程收到消息后&#xff0c;展示到终端上&#xff0c;并且将消息保存到文件上一份 create.c #include <myhead.h> int main(int argc,const char *argv[]) {if(mkfifo("./lin…

在windows下生成的mac苹果电脑端可以执行的unity项目程序,在mac电脑不能执行的修改方法

在windows下开发Unity项目&#xff0c;如果要执行的电脑是mac&#xff0c;必须在windows下生成for mac的程序&#xff0c;发现拷贝到mac电脑后不能执行&#xff1a; 原因是改程序没有mac的执行权限: 修改方法&#xff1a; 先打开终端&#xff1a; 进入文件所在目录 cd Downlo…

✅【文献串读】Object Counting论文串读

get宝藏博主&#xff1a;Tags - 郑之杰的个人网站 (0809zheng.github.io) 目标计数(Object Counting) - 郑之杰的个人网站 (0809zheng.github.io) 目录 1.《CountGD: Multi-Modal Open-World Counting》 2.&#xff08;2024CVPR&#xff09;《DAVE – A Detect-and-Verif…

报表控件stimulsoft操作:使用 Stimulsoft 产品连接到 OData 源

Stimulsoft Ultimate &#xff08;原Stimulsoft Reports.Ultimate&#xff09;是用于创建报表和仪表板的通用工具集。该产品包括用于WinForms、ASP.NET、.NET Core、JavaScript、WPF、PHP、Java和其他环境的完整工具集。无需比较产品功能&#xff0c;Stimulsoft Ultimate包含了…

FFmpeg实战 - 解复用与解码

大纲目录 文章目录 前置知识音视频基础概念解复用、解码的流程分析FFMPEG有8个常用库 常见音视频格式的介绍aac格式介绍&#xff08;ADTS&#xff09;h264格式分析FLV和MP4格式介绍 FFmpeg解码解封装实战数据包和数据帧&#xff08;AVPacket/AVFrame&#xff09;AVPacket/AVFra…

VHDX 安装操作系统

前言 使用 Win11 作为主力系统&#xff0c;再通过 VHDX 虚拟硬盘来安装另外的 Windows 系统。使用 VHDX 安装系统的好处在于&#xff1a;不影响原系统&#xff0c;用完即删。 需求 安装双系统&#xff0c;使用 VHDX 安装 WinServer 2022。 操作步骤 创建 VHDX 打开磁盘管…

一道笔试题 - 无重复字符的最长子串

老生常谈的一道题&#xff0c;常见并 文章目录 描述预期结果Java代码 描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长子串的长度。 预期结果 Java代码 import java.util.HashSet; import java.util.Set;public class Demo2 {public static void main(S…

为什么回测效果非常好的策略实盘却不行?

这是一个絮絮叨叨的专题系列&#xff0c;跟大伙儿唠一唠量化相关的小问题&#xff0c;有感而发写到哪算哪&#xff0c;这是第二期&#xff0c;来唠个12块钱的~ 之前在某乎看到这个问题&#xff0c;说的是自己的MACD策略回测绩效不错&#xff0c;但实盘比较拉胯&#xff0c;希望…

pxe666666

1.下载图形化工具 2.init 5进入 3.配个ip 4.安装图形化生成kickstart自动安装脚本的工具 5.配置httpd 6.浏览器查看 7.设置 保存 8.检查有无问题 9.共享 10.测试 11编辑配置文件37及后的脚本&#xff0c;并注释掉 27 28 12.安装pxe 13.共享pxelinux.0数据文件的网络服务 14.查询…

函数实例讲解(四)

文章目录 提取不重复值&#xff08;INDEX、MATCH、COUNTIF&#xff09;1、INDEX2、MATCH3、COUNTIF 提取不重复的值的经典套路&#xff08;LARGE、SMALL、ROW&#xff09;1、ROW2、LARGE3、SMALL&#xff09; 制作Excel动态查询表四舍五入函数(ROUND、ROUNDUP、ROUNDDOWN&#…

shell 环境变量

shell 变量加载顺序 set设置了当前shell进程的本地变量&#xff0c;本地变量只在当前shell的进程内有效&#xff0c;不会被子进程继承和传递。 env仅为将要执行的子进程设置环境变量。 export将一个shell本地变量提升为当前shell进程的环境变量&#xff0c;从而被子进程自动继…

搭建pxe网络安装环境

实验目的&#xff1a; 搭建pxe网络安装环境实现服务器自动部署 实验原理&#xff1a; PXE 网络安装环境实现服务器自动部署的实验原理为&#xff1a; 待安装的服务器&#xff08;PXE 客户端&#xff09;开机时&#xff0c;BIOS 设置从网络启动&#xff0c;向网络发送请求。…

54 GRE-VPN 点到点

一 理论 1 GRE 概念 GRE&#xff08;Generic Routing Encapsulation&#xff0c;通用路由封装&#xff09;协议用来对某种协议&#xff08;如IP、以太网&#xff09;的数据报文进行封装&#xff0c;使这些被封装的数据报文能够在另一个网络&#xff08;如IP&#xff09;中传…

职场“老油条”的常规操作,会让你少走许多弯路,尤其这三点

有句话说得好&#xff1a;“在成长的路上&#xff0c;要么受教育&#xff0c;要么受教训。” 挨过打才知道疼&#xff0c;吃过亏才变聪明&#xff0c;从职场“老油条”身上能学到很多经验&#xff0c;不一定全对&#xff0c;但至少有可以借鉴的地方&#xff0c;至少能让你少走…