Django中path()仅支持预设转换器且无正则边界控制,re_path()需手动写全^和$防误匹配;UUID用path('user/<uuid:pk>/')更安全;GET参数不应写入路由;视图中参数类型已转换但需自行校验范围与合法性。

URL动态路由怎么写才不踩正则坑
Django的path()和re_path()底层行为差异很大,用错一个就404或参数拿不到。别默认以为path()能匹配数字+字母混合ID——它只认str、int、slug等预设转换器,且不支持自定义正则边界控制。
-
path('user/<pk>/', ...)</pk>:安全,自动转整型,但只能匹配纯数字,/user/123a/直接404 -
re_path(r'^user/(?P<pk>\d+)/$', ...)</pk>:灵活,但^和$必须写全,漏掉$会导致/user/123/extra也匹配成功,pk却还是123 - 想匹配UUID?别手写
[0-9a-f\-]{36},用path('user/<pk>/', ...)</pk>更稳,Django自带校验 - 多个可选参数?比如
/search/?q=xxx&page=2——这不是路由该管的事,别往path()里硬塞q和page,那是GET参数
视图里怎么安全取URL里的参数
参数进了视图,不代表就能直接用。Django会按转换器类型帮你转,但没做空值或范围校验,出错常在运行时才暴露。
-
def user_detail(request, pk):中pk已是int类型(如果用了<pk></pk>),但可能是负数或超大数,数据库查前得加if pk 拦截 - 用
get_object_or_404(User, pk=pk)比手动try/except User.DoesNotExist省事,但注意:它不防SQL注入,只防对象不存在;参数本身仍需业务校验 - 如果路由是
path('post/<slug>/', ...)</slug>,slug变量是字符串,但可能含空格或中文(Django默认slug转换器只认ASCII字母、数字、下划线、连字符),真要支持中文请改用str或自定义转换器
GET和POST参数获取方式完全不同
很多人把request.GET.get('key')和request.POST.get('key')混着用,结果表单提交后取不到值,或者API调试时GET参数被当成POST处理。
-
request.GET是QueryDict,只读,对应URL问号后的键值对,如/list/?sort=date&limit=10→request.GET.get('limit')返回'10'(字符串) -
request.POST也是QueryDict,但只收application/x-www-form-urlencoded和multipart/form-data请求体,JSON接口的body内容不在里面,得用json.loads(request.body) - 统一取参?别偷懒写
request.GET.get('x') or request.POST.get('x')——GET和POST语义不同,合并逻辑容易掩盖bug;REST API建议只走request.GET或request.data(用DRF时) - 多值参数如
?tag=python&tag=django,用request.GET.getlist('tag'),不是get(),否则只拿第一个
为什么request.POST有时是空字典
不是代码写错了,大概率是前端没发对格式,或CSRF中间件拦住了。
立即学习“Python免费学习笔记(深入)”;
- 没带
Content-Type: application/x-www-form-urlencoded头?浏览器表单默认带,但fetch/fetch默认不带,得显式设置headers: {'Content-Type': 'application/x-www-form-urlencoded'} - CSRF验证失败:Django默认开启
CsrfViewMiddleware,POST请求必须带csrf_token(模板里用{% csrf_token %},API调用需从/csrf/接口取token并放header或body) - 用了
method="get"但写成request.POST取值?检查HTML表单method属性和视图里取参方式是否匹配 - 上传文件时忘了
enctype="multipart/form-data"?没这个属性,request.FILES为空,request.POST也收不到非文件字段
最常被忽略的是:URL路由参数、GET参数、POST body、JSON body、文件上传——它们在Django里压根不在同一个地方取,也没自动合并机制。写视图前先盯住请求方法和Content-Type,再决定从哪掏数据。











