DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • Django

    • 框架引入
    • 基本配置
      • Django三板斧
      • 静态文件配置
      • request对象
      • pycharm连接数据库
      • Django连接mysql
      • Django ORM
        • orm创建表
        • orm字段增删改查
      • 补充
        • 静态资源
        • 数据库连接池
        • 数据库读写分离
        • 手动的方式using
        • 基于router来实现
        • 分库
        • 多个app的情况
        • 单个app的情况
    • 单表记录CURD
    • 路由和视图层
    • 模版层
    • ORM查询
    • ORM字段
    • Ajax+layer
    • 自定义分页器
    • cookie与session
    • 中间件和csrf
    • Auth认证模块
    • ORM复习
    • 测试Demo
  • 第一次学drf

  • 第二次学drf

  • 温故知新

  • flask

  • 后端
  • Django
DC
2023-03-17
目录

基本配置

# Django三板斧

from django.shortcuts import render, HttpResponse, redirect
1> 返回字符串 return HttpResponse('ok')
2> 返回html文件/模版渲染文件 return render(request, 'home.html')
3> 重定向
return redirect('http://www.baidu.com') 外链地址
return redirect('/home/') 本地路由

提一嘴: render的本质还是将模版字符串放到HttpResponse中返回回去! 

在settings.py中检查应用是否注册、模版路径是否配置

INSTALLED_APPS = [
    ...
    ...
    'app01.apps.App01Config',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,  # -- 是否在App里查找模板文件!!
        ...
    }
]


# -- Ps:补充说明.
  在项目的根目录和app01下分别创建templates文件夹.
  根目录的templates通常存放公用的模板文件,以供各个App的模板文件调用,该模式符合代码重复使用的原则
  例如HTML中的<head>部分.
  app01下的templates是存放当前App所需要使用的模板文件.
  
'DIRS': [
    # -- replace('\\','/')是为了代码兼容win7系统等,跨平台.
    os.path.join(BASE_DIR, 'myblog/templates').replace('\\','/'),
    os.path.join(BASE_DIR, 'templates').replace('\\','/')
],
'APP_DIRS': True,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

mysite目录下的url.py

from django.conf.urls import url
from django.contrib import admin

from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^home/', views.home),
    url(r'^tobaidu/', views.to_baidu),
    url(r'^tohome/', views.to_home),
]
1
2
3
4
5
6
7
8
9
10
11
12

app01目录下的views.py
注意:每一个视图函数都必须有一个形参request.

from django.shortcuts import render, HttpResponse, redirect


def index(request):
    print(request)  # -- <WSGIRequest: GET '/index/'>
    return HttpResponse('ok')  # -- 返回字符串


def home(request):
    # -- 在templates目录下创建了home.html文件 body标签里写了-- 这是home!!
    return render(request, 'home.html')  # -- 返回html文件


def to_baidu(request):
    return redirect('http://www.baidu.com')  # -- 重定向跳转to某个网址


def to_home(request):
    return redirect('/home/')  # -- 重定向跳转to某个路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

http://127.0.0.1:8000/index/ -- 页面显示 ok
http://127.0.0.1:8000/home/ -- 页面显示 这是home!!
http://127.0.0.1:8000/tobaidu/ -- 跳转到百度搜索界面
http://127.0.0.1:8000/tohome/ -- 跳转到/home/路由


# 静态文件配置

我们都会使用动态导入!!这样只需要改STATIC_URL的属性值就行,而不需要改动html文件啦!

何为静态文件? css、js、jq、img、lib、sdk等都是静态文件!
在Django中,我们约定俗成的将html文件放到template目录中,静态文件放到static目录中!

我们以登陆的form表单为例.关键代码如下:

# ▲ mysite目录下的settings.py
# -- 静态文件配置,若想访问静态文件,就得以xxx开头/作为前缀!!
#    django看到你以/xxx/为前缀的路径,就晓得你想访问静态文件,没有其它意思.
#    但我们约定俗称配置为 STATIC_URL = '/static/' !!!
STATIC_URL = '/xxx/'
STATICFILES_DIRS = [
    # -- 这里的static就是指的根目录下的static文件夹
    os.path.join(BASE_DIR, 'static')
    # -- 当然可以写多个,依次从上往下找,找到就不找啦.跟环境变量一样,第一个找到了,就不会找第二个啦!
    # ...
]


# ▲ mysite目录下的urls.py
urlpatterns = [
    ...
    url(r'^login/', views.login),
]


# ▲ app01目录下的views.py
def login(request):
    return render(request, 'login.html')
  

# ▲ templates目录下的login.html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    {#    -- ◎ 使用BootCDN提供的免费CDN加速服务#}
    {#    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">#}
    {#    -- ◎ 静态导入#}
    {#    <link rel="stylesheet" href="/xxx/css/bootstrap.min.css">#}
    {#    -- ◎ 动态解析 {% load static %}中的static就是 STATIC_URL的值! 这里是'/xxx/' #}
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
</head>
<body>

<form action="">
    <p>username:<input type="text" name="username" class="form-control"></p>
    <p>password:<input type="text" name="password" class="form-control"></p>
    <input type="submit" value="登陆" class="btn btn-success">
</form>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

http://127.0.0.1:8000/xxx/css/bootstrap.min.css
http://127.0.0.1:8000/login/


# request对象

1> request.method -- 返回本次的请求方式,返回值是全大写的字符串 GET、POST.
2> request.POST -- 字典
     request.POST.get('表单的name属性值') -- 取最后一个
     request.POST.getlist('表单的name属性值') -- 可以接受全部数据 eg:多选框
3> request.GET

<!--
   action不填默认提交到当前地址,也就是views.py的login函数中!
   method不写,默认是get请求,表单里的k-v会拼接到路由中..
   input提交按钮不写type="submit",提交不到一点..
   post请求到后端,若用户名或者密码错误,后端重新render到登陆页面,页面会刷新,,表单内容清空!
   
   若提交的是button标签按钮,button的type属性值默认是submit,点击即可提交
   将button的type设置为button就不会自动提交
-->
<form action="" method="post">
    <p>username:<input type="text" name="username" class="form-control"></p>
    <p>password:<input type="password" name="password" class="form-control"></p>
    <p>
        {# ★ 若不给多选框设置value属性,勾选返回的都是on,设置后返回的是设置的值#}
        <input type="checkbox" name="hobbies" value="1"> 足球
        <input type="checkbox" name="hobbies" value="2"> 篮球
        <input type="checkbox" name="hobbies" value="3"> 排球
    </p>
    <input type="submit" value="登陆" class="btn btn-success">
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

先注释中间件中的csrf验证!!不然post请求通过不了!!
Ps: mysql三大攻击 -- xss、sql注入、csrf

★ 输入网址http://127.0.0.1:8000/login/, 走的是login函数渲染出模版..
提交表单,表单的action的值为空,提交到当前地址,即http://127.0.0.1:8000/login/.会再走到login函数.
所以我们需要在login函数中判断请求的方式!!!
当然可以设置action的值为/login_post/,专门写个路由和函数处理表单的post请求,但没有必要!!

def login(request):
    # -- !!应该区分不同的请求(get/post)方式,做不同的事情!
    #    1> get请求来的时候,只渲染一个登陆页面!
    #    2> post请求来的时候,接收参数!
    # -- 那如何区分不同的请求方式呢?
    #    通过request.method的值来判断
    #    输入网址 http://127.0.0.1:8000/login/,回车,此处打印值 GET <class 'str'>
    #    填写表单信息,点击登陆 会再次执行该函数,此处打印值 POST <class 'str'>
    print(request.method, type(request.method))
    # -- POST
    if request.method == "POST":
        # <QueryDict: {'username': ['egon'], 'password': ['123'], 'hobbies': ['2', '3']}>
        print(request.POST)
        # <class 'django.http.request.QueryDict'> -- 简单理解就是字典!
        # -- 实验了下,没对应的key,默认返回值跟原生字典一样为None
        print(type(request.POST))
        # -- 接收用户表单中提交的用户名和密码
        username = request.POST.get('username')
        password = request.POST.get('password')
        # -- 若用get只会接收最后一个;getlist接收多个值!
        hobbies = request.POST.getlist('hobbies')
        print(username, password, hobbies)  # egon 123 ['2', '3']
        if username == 'egon' and password == int('123'):
            # -- 一系列的处理逻辑
            pass
    # -- GET
    #    http://127.0.0.1:8000/login/?name=egon&age=20
    # <QueryDict: {'name': ['egon'], 'age': ['20']}>
    print(request.GET, type(request.GET))
    # <class 'django.http.request.QueryDict'>
    print(type(request.GET))
    # -- 当然也有request.GET.getlist(..)
    name = request.GET.get('name')
    age = request.GET.get('age')
    print(name, age)  # egon 20

    return render(request, 'login.html')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# pycharm连接数据库

数据库 -- 加号 -- 数据源 -- mysql -- 弹出页面中的名称那一栏自己随便填...
比如:这里我连接的是数据库中名为youku的数据库,连接时名称填写的是mysite_db!

Ps: 通常不会这么用,看个人.. 一般都在Navicat中操作啦!!


# Django连接mysql

"""
1> 安装mysql,启动mysql服务
2> 可以使用navicat连接mysql服务,连接好后创建一个名为"db"的数据库
3> 在Django配置文件中进行配置
4> 安装相关依赖/第三方组件
"""

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db',  # -- 库名
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'CHARSET': 'utf8'
    }
}

Ps: 查看Django支持哪些数据库,from django.db.backends import mysql 查看源码,那些文件夹名就是支持的数据库.
    不够用,需要的是这些之外的数据库?在源码中将那个数据库的引擎放到这些数据库的同级目录下.
postgresql安装的是 pip install psyopg2
oracle安装的是 pip install cx-Oracle
`https://pypi.org/`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

在Django项目启动的时候,会报错: No module named MySQLdb
解决方案: 安装pymysql模块并在app01的__init__.py下添加以下代码.
但很多时候, 也会在 项目根目录/项目名目录/__init__.py下添加一下代码.

import pymysql

# -- 默认用的是mysqldb,改成pymysql
pymysql.install_as_MySQLdb()
1
2
3
4

# Django ORM

ORM 对象关系映射
作用: 将原生sql语句转成代码操作sql,本质是执行sql语句.

代码 数据库
类 表
类的属性 表里字段对应的值
类的实例对象 表里的记录

# orm创建表

1> 在settings.py中配置好 Django连接mysql中的db数据库 的相关内容,db数据库事先通过navicat建好!
2> ORM的书写位置 -- models.py

# -- app01下的models.py
from django.db import models


# -- 必须继承models.Model!!
class User(models.Model):
    # -- id int primary key auto_increment
    id = models.AutoField(primary_key=True)
    # -- name varchar(64)
    #    强调!!CharField的max_length参数必须指定!
    name = models.CharField(max_length=64)
    # -- password varchar(32)
    password = models.CharField(max_length=32)
1
2
3
4
5
6
7
8
9
10
11
12
13

3> 生成迁移记录与迁移 在终端依次输入命令(manage.py所在路径下)
python3 manage.py makemigrations -- 会在app01.migrations文件夹下生成0001_initial.py文件
python3 manage.py migrate
-- 运行此命令后, 会读取migrations下0001_initial.py里的配置, 转换成sql语句,在default对应的数据库中生成表
ps: 若有多个app,会依次读取每个app下migrations目录下最新py文件里的配置. 在default对应的数据库中生成表..

说明: app01_user 即app名字_类名小写 是我们自己创建的表,其余是Django每次迁移时默认自动生成的表...
自动生成的表来自settings.py INSTALLED_APPS属性中默认注册的那些app!!! 当前可以在迁移前注释掉,不用它们!
django_migrations 这张表里是数据迁移的记录..

注意: 切勿通过数据库可视化工具修改表结构.. 应该通过修改ORM对应的表,然后进行数据迁移来修改..
不然手动修改表结构, 而ORM表没改, 调用通过ORM创建的表时, 传入的字段不存在, 会报错.

# orm字段增删改查

每次改变models.py中跟数据有关的代码,都需要执行数据库迁移相关的两条命令!!

注意! Django ORM 设置的字段默认不允许为空;用sql写的原生语句默认允许为空!!

▲ 在User类中依次进行以下实验!!
    # -- 增加一个age字段,重新执行两条命令
    #    ★ 生产迁移记录的时候,会让我们设置一个该字段的值(一次性的),作为该表每行数据的age字段的值
    age = models.IntegerField()
    # -- 当然,我们可以在增加age字段时,设置可为空,或者设置默认值!!!!!!
    #    age = models.IntegerField(null=True)
    #    age = models.IntegerField(default=1)
    
    
    # -- 修改,需要重新执行两条命令
    age1 = models.IntegerField()
    
    # -- 删除,直接注释掉,然后重新执行两条命令 生产环境中此操作很危险,慎重!
    age1 = models.IntegerField()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Ps: 可以简化执行两条命令的操作.
pycharm Tools - Run manage.py Task 在下方弹出的窗口中,执行命令 makemigrations、migrate


# 补充

# 静态资源

静态资源, 大致可以分为两类:
1> 开发需要的css、js、img -- 根目录下的/static/ ; 已注册的app目录下的/static/.
2> 媒体文件,即用户上传的数据.图片、音频、视频等 -- 根目录下的/media/

static

STATIC_URL = '/xxxx/'  # 一般为"/static/"
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

优先在STATICFILES_DIRS中找,没找到就去已注册的app下找static目录!
一般性规则:若是多app,每个app的static目录下应该嵌套一层app名字的目录.. 
eg:模版中使用
   {% load static %}
   # Django会自动找到配置文件中的STATIC_URL,自动拼接,相当于src='/xxxx/web/1.png'
   <img src='{% static 'web/1.png' %}'>
1
2
3
4
5
6
7
8
9
10
11

media

"""
以下是查看媒体文件的配置
"""

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
                  path('api/', include("apps.api.urls", namespace='x1')),
              ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

<img src='/media/aa.png'> 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 数据库连接池

官方文档: https://pypi.org/project/django-db-connection-pool/

每次操作数据库,都要创建连接,发收消息,关闭连接.. 很浪费资源,所以需要数据库连接池.

pip install pymysql 记得写那个猴子补丁.
pip install django-db-connection-pool

DATABASES = {
    "default": {
        'ENGINE': 'dj_db_conn_pool.backends.mysql',
        'NAME': 'day04',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root123',
        'HOST': '127.0.0.1',  # ip
        'PORT': 3306,
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,     # 最小,Django运行起来,就与数据库建立10个连接
             # 在最小的基础上,不够用,还可以增加10个 即:最大20个. 
             # So,支持20的并发.再多就得等待.等某个连接用完后交还到连接池中.
            'MAX_OVERFLOW': 10,  
            'RECYCLE': 24 * 60 * 60,  # 一个连接可以被重复用多久,超过会重新创建,-1表示永久.
            'TIMEOUT':30,  # 池中没有连接最多等待的时间.单位s.
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

组件django-db-connection-pool 内部最核心的是一个支持SQLAchemy数据库连接池的组件.

# 数据库读写分离

两个数据库拥有同样的表结构..两数据库实现数据同步. 一数据库用来读,一数据库用来写.

为了配合数据库架构的...

setting文件中数据库的配置如下

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': BASE_DIR / 'db.sqlite3',
    # }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db1',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'CHARSET': 'utf8'
    },
    'db2': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db2',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'CHARSET': 'utf8'
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

一点准备工作

数据库之间的同步,参考资料:
   https://zhuanlan.zhihu.com/p/89796383
   https://www.bilibili.com/video/BV1Kr4y1i7ru/?p=161
  
  
1.准备两台服务器.
192.168.1.2   主/master  - 名为db1的数据库 用来写
192.168.2.12  从/slaver  - 名为db2的数据库 用来读
可在mysql中创建名为db1和db2的两个数据库来模拟.


2.数据表结构 apps/app01/models.py
from django.db import models
class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32)

 
3.生成数据库表,执行一下命令
  python manage.py makemigrations
  python manage.py migrate 等同于 python manage.py migrate --database=default
  python manage.py migrate --database=db2
  这样的话,在db1、db2两个数据库中都有了相同的表!!

 
4.总路由
from django.urls import path
from apps.app01 import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('index/', views.index),
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 手动的方式using
"""
视图函数 apps/app01/view.py
"""
from django.shortcuts import HttpResponse
from . import models

def index(request):
    # 往主数据库db1里写入数据 默认就是using("default")
    models.UserInfo.objects.using("default").create(name="麻瓜")
    # 往从数据库db2里读取数据,db1和db2会做配置进行数据同步,同步的慢些的话,是读不到最新数据的.
    # 注:Django可不管主从数据库之间数据的同步,数据库之间的同步是运维的活,与开发无关.
    res = models.UserInfo.objects.using("db2").all()
    print(res)
    return HttpResponse("Hello World!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基于router来实现

最终效果: 利用ORM语句对数据库进行CURD时, ORM语句不用写using()..

step1: 在项目根目录创建utils目录,在该目录下创建router.py
step2: 往router.py里写入内容
step3: 在setting.py里注册router DATABASE_ROUTERS = ['utils.router.DemoRouter']

"""
utils/router.py
"""
class DemoRouter:
    # !!可以添加逻辑判断动态的控制,细粒化的控制某个app的某张表进行读操作时从哪个数据库里读取..
    def db_for_read(self, model, **hints):
        print(model._meta.app_label)  # app01 -- 表明当前ORM语句操作的是哪个app
        print(model._meta.model_name)  # userinfo -- 表明当前ORM语句操作的是哪个model
        """
        想要知道model._meta里还有什么东西,通过.没有提示 有个小技巧.
        可以查看model._meta的类型,即它是哪个类的实例化对象,去看该类里面定义了什么.
        """
        # app01.userinfo <class 'django.db.models.options.Options'>
        # from django.db.models.options import Options 跳转到Options里查看
        print(model._meta, type(model._meta))
        print(hints)
        # return None  # 去下一个Router中找
        return 'db2'  # 返回读的那个数据库

    # 写操作同理,也可以细粒化的控制.
    def db_for_write(self, model, **hints):
        # model._meta
        return "default"  # 返回写的那个数据库
      
      
"""
视图函数 apps/app01/view.py
"""
from django.shortcuts import HttpResponse
from . import models

def index(request):
    models.UserInfo.objects.create(name="麻瓜")
    res = models.UserInfo.objects.all()
    print(res)
    return HttpResponse("Hello World!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 分库

业务比较大, 总共有百来张表, 想要拆分到不同的数据库中
注意!! 一定不要跨数据库进行表关联.. 数据库支持,但Django是不支持的!!! 尽可能的将用关联的表放到同一个数据库中.

# 多个app的情况

假设共100张表, 50张表放到app01; 50张表放到app02中.
表先通过app隔离, 然后将不同的app迁移到不同的数据库中. 比如: app01中的表到db1; app02中的表到db2.

^先来探究下这几个命令:
  # 运行该命令后,每个app下migrations目录里会生成配置文件
  python manage.py makemigrations  
  # <将每个>app下migrations目录里生成的配置文件转化为sql语句,都在default对应的数据库中生成表
  python manage.py migrate 等同于 python manage.py migrate --database=default 
  # <只是>将app01这个app下migrations目录里生成的配置文件转化为sql语句,在default对应的数据库中生成表
  python manage.py migrate app01 --database=default
1
2
3
4
5
6
7

准备工作

"""
apps/app01/models.py
"""
from django.db import models
class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32)
    
"""
apps/app02/models.py
"""
from django.db import models
class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)

    
python manage.py makemigrations 
python manage.py migrate app01 --database=default
python manage.py migrate app02 --database=db2
>>: 最终结果,将app01中的表放到了db1数据库中,app02中的表放到了db2中.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

读写操作

注:虽然上面进行了分库操作,但是Django的ORM语句可不管分没分库、读写有无分离
  无论在哪个app里,对表进行CURD的ORM语句依旧默认使用的是using("default")
  若刚好这个表没有在default对应的数据库中,就会报错..
这里体现在,from apps.app02 import models as m2  m2.Role.objects.all() 无论在哪个app的model里写这行语句都会报错
报错信息:(1146, "Table 'db1.app02_role' doesn't exist")
  
比较low的解决办法,m2.Role.objects.using("db2").all()
比较好的解决办法,app里的所有表是放到某个数据库里的嘛,所以某app是跟某个数据库一一对应的.
class DemoRouter:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == "app01":  # -- 表明当前ORM语句操作的是哪个app
            return "default"
        if model._meta.app_label == "app02":
            return "db2"

    def db_for_write(self, model, **hints):
        if model._meta.app_label == "app01":
            return "default"
        if model._meta.app_label == "app02":
            return "db2"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 单个app的情况

我想让userinfo表放到db1; role和goods两张表放到db2.
解决办法: 命令 + router

"""
apps/app01/models.py
"""
from django.db import models
class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32)

class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)

class Goods(models.Model):
    price = models.CharField(verbose_name="价格", max_length=32)
    

    
"""
utils/router.py 记得在settings.py文件中注册
"""
class DemoRouter:
    # -- 借助这个函数进行的分库
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if db == "db2":
            if model_name in ["role","goods"]:
                return True
            else:
                return False

        if db == "default":
            if model_name in ["userinfo"]:
                return True
            else:
                return False
              
    # 读操作
    def db_for_read(self, model, **hints):
        if model._meta.model_name in ["role","goods"]:
            return "db2"
        if model._meta.model_name in ['userinfo']:
            return "default"

    # 写操作
    def db_for_write(self, model, **hints):
        if model._meta.model_name in ["role","goods"]:
            return "db2"
        if model._meta.model_name in ['userinfo']:
            return "default"
              

-- 接着,执行命令
执行命令 python manage.py migrate app01 --database=default
即db为"default",接着遍历app01.models里的所有表,表名为userinfo的在数据库db1中生成

执行命令 python manage.py migrate app01 --database=db2
即db为"db2",接着遍历app01.models里的所有表,表名为"role","goods"的在数据库db2中生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

框架引入
单表记录CURD

← 框架引入 单表记录CURD→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式