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

  • 第一次学drf

  • 第二次学drf

  • 温故知新

    • 学习计划
    • 常见问题及配置
      • 常见报错
        • 创建Django项目
        • 迁移项目
        • Pychram查看sqlite
        • 模块导入问题
        • 线上线下配置文件
      • 常见配置 - settings
        • 中文和时区
        • static
        • media
        • Django连接mysql数据库
        • 数据库连接池
        • redis
      • 常用操作
        • 测试环境搭建
        • ☆ 快速创建新项目
        • 开启事务代码
        • ☆ 剖析源码技巧
    • 数据表设计经验
    • Django精简总结
    • 源码知识点
    • drf通篇概览
    • drf-前篇
    • drf-后篇
  • flask

  • 后端
  • 温故知新
DC
2024-05-12
目录

常见问题及配置

将常见的一些报错和配置归纳到此处, 方便用到时直接粘贴复制!!

# 常见报错

# 创建Django项目
mac通过pycharm创建时,自动填充的是这样的 -- 'DIRS': [BASE_DIR / 'templates']
导致项目启动不起来!直接报错
    'DIRS': [BASE_DIR / 'templates']
    TypeError: unsupported operand type(s) for /: 'str' and 'str'
解决方案 -- 将其改为 'DIRS': [os.path.join(BASE_DIR,'templates')]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,  # -- 是否在App里查找模板文件!!
        ...
    }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 迁移项目
注意: 切勿通过数据库可视化工具修改表结构.
应该通过修改ORM对应的表,然后进行数据迁移来修改!!
不然手动修改表结构, 而ORM表没改, 调用通过ORM创建的表时, 传入的字段不存在, 会报错.
1
2
3
# Pychram查看sqlite
- 在pychrm查看sqlite数据库时,下载对应的驱动可能失败,换一个低点版本试试!!
- 注意: 在sqlite数据库添加字段类型为DateField的数据时会转成时间戳,这可能是个bug,不是你的问题.
1
2
# 模块导入问题
在pycharm中,模块导入飘红, 并不一定是代码问题!
>> 解决方案: 将 py文件/脚本 里飘红的导入路径, 自动加入环境变量!!
   具体操作: 在settings.py文件中,类似于这样操作 -->
            import sys
            sys.path.append(BASE_DIR)
            sys.path.append(os.path.join(BASE_DIR, "apps"))
   原理: 
       导入模块的路径, 需要从环境变量下开始导 -- 绝对导入 
       导入模块时,模块的查找顺序,会依次从内存、内置模块、"sys.path"环境变量中找.
        
经验之谈:
1. pycharm应该打开到项目根目录的
2. 可以将文件夹声明为Python的包,也就是需要在文件夹内创建一个__init__.py空文件.
1
2
3
4
5
6
7
8
9
10
11
12
13

举个例子:

djangoProject
├── app01
│   ├── models.py
│   └── views.py
├── djangoProject
│   └── settings.py
└── manage.py

因为django项目的manage.py是入口文件,该文件会先加载settings.py
settings.py里会通过sys模块将项目的根目录(即manage.py所在目录)加载到环境变量中.
So,在views.py中像以下的格式编写导入语句皆是可以的!!
from app01.models import User  # - 借助环境变量进行绝对导入
from .models import User  # 相对导入

注: 关于包
- 在包内部,尽量使用相对导入!!
  好处1 >> 这样的话,不管包移到哪里去,包里面的导入代码都不用改!! 
          若使用的绝对导入,移动后,绝对导入所在的路径不在环境变量中,就会报错.  
  好处2 >> 以最短的路径导入,这样可以尽可能有效的避免循环导入!!(因为导入时会执行里面的代码)
          - 在包里有文件a和b, a.py导入b.py中的,b.py导入a.py中的,哪怕写成相对导入的格式,也会判定为循环导入哦!!
  Q: 我们发现有些第三方包里并没有用相对导入啊!!下载下来为啥不报错呢?  
  A: 因为将第三方包下载下来后, 第三方包所在路径就加入到环境变量中啦!!!  
- 特别特别注意: 使用相对导入的py文件不能作为脚本运行!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 线上线下配置文件
有两个方案
-
-
1
2
3

# 常见配置 - settings

# 中文和时区
若想将错误信息的显示从英文变为中文.需将配置文件中 LANGUAGE_CODE = 'en-us' 改为 LANGUAGE_CODE = 'zh-hans'.
- 纯净版 + 改一下时区,中文
  """
  LANGUAGE_CODE = 'en-us' 英文
  LANGUAGE_CODE = 'zh-hans' 中文
  """
  LANGUAGE_CODE = 'zh-hans'
  """
  datetime.datetime.now() - utc时间 / datetime.datetime.utcnow() - utc时间
  TIME_ZONE = 'UTC'
  datetime.datetime.now() - 东八区时间 / datetime.datetime.utcnow() - utc时间
  TIME_ZONE = 'Asia/Shanghai'
  """
  TIME_ZONE = 'Asia/Shanghai'
  USE_I18N = True
  USE_L10N = True
  """
  影响自动生成数据库时间字段
  USE_TZ = True, 创建UTC时间写入到数据库
  USE_TZ = False, 根据TIME_ZONE设置的时区进行创建时间并写入数据库
  """
  USE_TZ = False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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/css/bootstrap.min.css'
   <img src='{% static 'css/bootstrap.min.css' %}'>
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
# Django连接mysql数据库

1> 安装mysql,启动mysql服务

以后想使用mysql,mac终端在任意目录下执行三条命令
- source ~/.zhsrc
- mysqlstart       (执行命令mysqlstop停止)
- mysql -uroot -p  (初使密码 admin1234)
1
2
3
4

2> 可以使用navicat连接mysql服务,连接好后创建一个名为 db 的数据库

3> 在Django配置文件中进行配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db',  # -- 库名
        'USER': 'root',  # -- 公司里不会用root用户
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'CHARSET': 'utf8'
    }
}
1
2
3
4
5
6
7
8
9
10
11

4> 安装相关依赖/第三方组件. pip install pymysql 并 进行 猴子补丁!

"""
安装pymysql模块并在app01的__init__.py下添加以下代码.
但很多时候, 也会在 项目根目录/项目名目录/__init__.py下添加以下代码.
"""
import pymysql

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


# 若启动项目后会报错: AttributeError: 'str' object has no attribute 'decode'
# !!!修改源码. 大致位置python3.8/site-packages/django/db/backends/mysql/operations.py
# 不用刻意去找,在pycharm报错的地方直接点进去就行..
"""
if query is not None:
    # query = query.decode(errors='replace')  # -- 需要修改的地方
    query = query.encode(errors='replace')    # -- 修改后的样子
return query
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

PS: 查看Django支持哪些数据库, from django.db.backends import mysql查看源码,那些文件夹名就是支持的数据库.
不够用,需要的是这些之外的数据库?在源码中将那个数据库的引擎放到这些数据库的同级目录下.

# 数据库连接池

每次操作数据库,都要创建连接,发收消息,关闭连接.. 很浪费资源,所以需要数据库连接池.
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
# redis
CACHES = {
    "default": {  # -- ▲ 这里default
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100},
            "PASSWORD": "qwe123",
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 常用操作

# 测试环境搭建

测试环境的准备: 去manage.py中拷贝前四行代码!然后自己再写两行!

import os
import sys

if __name__ == "__main__":
    # -- 通过环境变量DJANGO_SETTINGS_MODULE来告知Django使用哪个配置
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tem.settings")
    import django

    # -- 若独立运行的python脚本是需要依赖django中的一些配置,那么就需要用到django.setup()
    #    运行到django.setup()该行代码才表明测试环境已经准备好了!!
    django.setup()

    # -- !!所有的测试代码必须都写在测试环境准备好后,否则不生效!
    #    也就是写在django.setup()这行代码之后呗!
    # ... ... ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ☆ 快速创建新项目
- pychram创建python项目 + 虚拟环境
- pip install django==3.2
  pip install djangorestframework==3.12.4
- 1.在项目根目录下 django-admin startproject dig_2 .  (有个点哈!!
  2.在项目根目录下 python manage.py startapp api      (api换成自己的app名字
  3.配置django快捷启动!! 注:项目根目录、选到setting.py文件
  4.在项目根目录下,创建apps文件夹 将上一步创建的app移到该目录下 + 改一下app.py + 注册app 
    (eg:'apps.api.apps.ApiConfig', 'rest_framework',) 
  5.根路由文件里添加路由 eg: path('api/', include('apps.api.urls')),
- 启动项目看有没有问题!!
1
2
3
4
5
6
7
8
9
10

视图的结构.我们采用 views文件夹 + 多个业务文件夹..
比较懒,多个业务文件夹创建和基础代码我让程序来实现..

import os


def create_files(target_folder, folder_name):
    """创建目标文件夹及其下的 Python 文件,并在 routers.py 中写入内容"""
    if not os.path.exists(target_folder):
        os.makedirs(target_folder)
        print(f"创建文件夹: {target_folder}")

        files = ['routers.py', 'serializers.py', 'views.py']
        for file_name in files:
            file_path = os.path.join(target_folder, file_name)
            with open(file_path, 'w') as f:
                if file_name == 'routers.py':
                    # 写入特定内容到 routers.py
                    f.write(f"""from django.urls import path
from rest_framework import routers
from . import views

router = routers.SimpleRouter()
router.register(r'{folder_name}', views.{folder_name.capitalize()}View, '{folder_name}')

urlpatterns = []
urlpatterns += router.urls
""")
                elif file_name == 'serializers.py':
                    # 提取模块路径并写入内容到 serializers.py
                    module_path = '.'.join(base_path.rstrip(os.sep).split(os.sep)[-3:-1])
                    class_name = folder_name.capitalize() + 'Serializer'
                    f.write(f"""from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from {module_path} import models

class {class_name}(serializers.ModelSerializer):
    class Meta:
        model = models.{folder_name.capitalize()}
        fields = '__all__'
""")
                elif file_name == 'views.py':
                    f.write(f"""from rest_framework.viewsets import ViewSetMixin
from rest_framework.views import APIView

class {folder_name.capitalize()}View(ViewSetMixin, APIView):
    pass
""")
            print(f"创建文件: {file_path}")


def build_include_path(base_path, folder_name):
    """构建 Django include 路径"""
    path_parts = base_path.rstrip(os.sep).split(os.sep)
    last_three_parts = path_parts[-3:]
    include_path = '.'.join(last_three_parts) + '.' + folder_name + '.routers'
    return include_path


def update_urls_file(urls_file_path, new_path_str):
    """更新 urls.py 文件的 urlpatterns 列表"""
    lines = []
    inside_urlpatterns = False

    # 读取现有文件内容
    with open(urls_file_path, 'r') as f:
        lines = f.readlines()

    # 写入更新后的内容
    with open(urls_file_path, 'w') as f:
        for line in lines:
            if 'urlpatterns = [' in line:
                inside_urlpatterns = True
                f.write(line)
                f.write(f'    {new_path_str}\n')
            elif inside_urlpatterns and line.strip() == ']':
                inside_urlpatterns = False
                f.write(line)
            else:
                f.write(line)


def create_or_update_urls_file(parent_folder, new_path_str):
    """创建或更新 urls.py 文件"""
    urls_file_path = os.path.join(parent_folder, 'urls.py')

    if not os.path.exists(urls_file_path):
        # 创建 urls.py 文件并写入内容
        with open(urls_file_path, 'w') as f:
            content = f"""from django.urls import path, include
urlpatterns = [
    {new_path_str}
]
"""
            f.write(content)
        print(f"创建文件: {urls_file_path}")
    else:
        # 更新现有 urls.py 文件
        update_urls_file(urls_file_path, new_path_str)
        print(f"更新文件: {urls_file_path}")


def create_files_and_update_urls(base_path, folder_name):
    """主函数:创建文件夹和文件,并更新 urls.py"""
    target_folder = os.path.join(base_path, folder_name)
    create_files(target_folder, folder_name)

    include_path = build_include_path(base_path, folder_name)
    new_path_str = f"path('{folder_name}/', include('{include_path}')),"

    parent_folder = os.path.dirname(base_path)
    create_or_update_urls_file(parent_folder, new_path_str)


if __name__ == '__main__':
    base_path = '/Users/dengchuan/Desktop/dig_2/apps/api/views'
    folder_name = 'info'
    create_files_and_update_urls(base_path, folder_name)
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 开启事务代码

1> 在with代码块中写的所有SQL语句都属于同一个事务;
2> 经验之谈: 在事务中,尽量只写sql语句,业务逻辑代码写在事务外面!!否则数据量一大,逻辑一复杂,会出错!!

from django.db import transaction

try:
    with transaction.atomic():
        pass
        # -- sql1
        # -- sql2
except Exception as e:
    print(e)
1
2
3
4
5
6
7
8
9
# ☆ 剖析源码技巧
- 直接在视图函数的类的get方法中写 self.dispatch,跳转过去即可!!
- APIView类里有很多默认的配置,点击跳转api_settings,可以看到配置名‘REST_FRAMEWORK’
- 认证权限限流的全局和局部配置的配置名可以去APIView类里找
  比如: authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
     (等号左边是局部的,右边是全局的!!!)
  另外,authentication_classes结尾是es,表示是复数,那么其值是多个,局部和全局都用[];
     若结尾没有es,局部和全局的其值就是一个字符串!
1
2
3
4
5
6
7

重写方法

class UserSerializer(serializers.ModelSerializer):    
    class Meta:
        model = models.UserInfo
        fields = ["id", 'name',"age"]

    def get_fields(self):           # -- 重写该方法
        res = super().get_fields()  # -- 利用super,保证源码的正常运行.
        print(res)                  # -- 在此处打印 
        return res
1
2
3
4
5
6
7
8
9

pycharm debug模式打断点.

image-20230824102327451

右键点查找用法

image-20230824151514964


学习计划
数据表设计经验

← 学习计划 数据表设计经验→

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