V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
elboble
V2EX  ›  Django

Django 怎么做同一个 url,对应不同的 view 函数?

  •  
  •   elboble · 2022-08-29 16:16:31 +08:00 · 2757 次点击
    这是一个创建于 796 天前的主题,其中的信息可能已经有所发展或是发生改变。

    类似于那种定时抢购的逻辑。

    时间没到之前是个介绍页面,时间到了之后进入真正的 view 处理函数。

    触发条件不一定是时间,也可能是后台控制的。就是要做到程序不重启,同一 url 对应的 view 变了。

    我是这样做的,加了个全局变量,然后在 url 对应个 view 函数里做判断,后台改变这个全局变量,执行不同的 view 函数。

    IS_RELEASE 是全局变量,entrance 函数是入口函数,release 函数是改变入口的视图函数。

    IS_RELEASE = False

    def entrance(request):
      global IS_RELEASE
      if IS_RELEASE:
       return index2022(request)
      else:
      return index2(request)

    @login_required
    def release(request):
    global IS_RELEASE
    if IS_RELEASE:
    IS_RELEASE = False
    else:
    IS_RELEASE = True
    return redirect("/conf/")

    这个方法在本地调试没问题,但是上到服务器后,出现执行 release 函数后 IS_RELEASE 没按预期改变,或者有秒级的延迟,我猜是不是有 cdn 的影响,但是这个都应该是动态页面,每个请求都要回服务器处理的。

    14 条回复    2023-11-02 11:25:06 +08:00
    676529483
        1
    676529483  
       2022-08-29 16:22:18 +08:00
    你服务器肯定不是 runserver 启动的吧?走 gunicorn 、uwsgi 等等,都是多进程的,全局变量只是进程唯一的,可以改成从一个地方去拿,比如 redis 、mysql
    elboble
        2
    elboble  
    OP
       2022-08-29 16:24:20 +08:00
    @676529483 是的 supervisor 启动的
    676529483
        3
    676529483  
       2022-08-29 16:25:32 +08:00
    @elboble supervisor 只是进程管理,启动命令可以贴下
    elboble
        4
    elboble  
    OP
       2022-08-29 16:40:35 +08:00
    [uwsgi]
    chdir = /home/xxxx/project/xxxx
    module = xxxx.wsgi
    home = /home/xxxx/venv/venv3.9
    master = true
    processes = 2
    socket = 0.0.0.0:8909
    vacuum = true
    zxzflower
        5
    zxzflower  
       2022-08-29 16:53:46 +08:00
    用 redis 或者数据库 做个访问开关,你只要有多个 worker ,你的方法就会混乱的,甚至 worker 还会 restart
    bulay
        6
    bulay  
       2022-08-29 16:57:37 +08:00
    如果是单台服务器直接用 django.core.cache,本地缓存.
    AndyVTEX
        7
    AndyVTEX  
       2022-08-29 17:45:35 +08:00
    是啊,肯定是 redis 或者数据库开关呀,环境变量是什么骚操作
    lanlanye
        8
    lanlanye  
       2022-08-29 20:04:43 +08:00 via iPhone
    建议你把要渲染的模板做成 Model ,需要时直接去 DjangoAdmin 里改……
    elboble
        9
    elboble  
    OP
       2022-08-29 23:42:09 +08:00
    感谢各位大佬,用 redis 存了状态,基本实现了功能,上服务器也没问题了。

    还有几点请教:
    1 ,用 uwsgi 起多个 worker ,实际上是多个 django 的实例在跑,这样如果用 uwsgi 来启动 django ,djaongo 中是不存在只运行一次的代码。
    我这个问题中,即使用 redis 也有个初始值的坑。最简单的是在程序之外,程序启动之前,用 redis-cli 手动设定初始值。如果不用这个方法,就想是不是能在 django 初始化的地方,运行一次 redis set 初始值。通过上面的分析,django 用 uwsgi 启动是不存在这样只执行一次的代码,至少每个 worker 启动 django 所有的代码都要跑一遍,有几个 worker 就要跑几遍。
    后来我想通过 redis 直接 get 键取值,但是 redis 的 get 不像 json 的 get 读取空时能返回一个默认值,这个真没想到,自己简单包装了一个能返回默认值的,来代替原始的 conn.get()。这样就不需要预先设置 redis 了。
    conn = redis.Redis(connection_pool=POOL)
    IS_RELEASED_KEY = 'xxxx_is_released'
    def rget(key):
    ret = conn.get(key)
    if ret == None:
    return '0'
    else:
    return ret

    2 ,取得 redis 的 conn 是在 view.py 中,但是不在任何一个 view 函数中,这个代码是不是每个 worker 只执行一次,有几个 woker 就有几个不同的 conn ,还是每次请求都会建新的 conn ?
    zmaplex
        10
    zmaplex  
       2022-08-31 16:45:15 +08:00 via Android
    一个小功能还是不要上 redis 了吧,在 django 中类似全局变量效果,请直接用 django 内置的
    cache 。
    elboble
        11
    elboble  
    OP
       2022-08-31 23:36:14 +08:00
    @zmaplex redis 本来就开了,给 celery 用的,这个比建个表 migrate 方便点。
    gaogang
        12
    gaogang  
       2022-09-05 18:01:59 +08:00
    @elboble uwsgi 启多个 worker 不是 preload 的方式,所以这种写法的话,每个 worker 中在使用到 view.py 时会创建一个 conn
    programMrxu
        13
    programMrxu  
       2023-11-01 17:20:21 +08:00
    为什么这里的值不会改变呢?我在本地跑了两个线程,去修改一个全局变量,他的值是会发生变化的。
    elboble
        14
    elboble  
    OP
       2023-11-02 11:25:06 +08:00
    @programMrxu 我理解是 uwsgi 接受每个请求,是单独开个 django 进程,所以即使全局变量也不能共享,“全局”仅在 django 进程内。所以用系统级的 redis ,杀鸡用牛刀了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   926 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 21:24 · PVG 05:24 · LAX 14:24 · JFK 17:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.