代码之家  ›  专栏  ›  技术社区  ›  kurtgn

如何取消缓存Django模型

  •  0
  • kurtgn  · 技术社区  · 8 年前

    我有一个叫 Chat 可以从自身存储和检索Cookie,如下所示:

    >>> chat = Chat.objects.get(pk=43265)
    >>> chat.cookies
    >>> chat.set_cookie('1','2')
    >>> chat.cookies
    '{"1": "2"}'
    

    这个 set_cookies 方法是用一个简单的 json.dumps :

    def set_cookie(self, key, value):
        if self.cookies:
            current_cookies = json.loads(self.cookies)
        else:
            current_cookies = dict()
        current_cookies.update({key: value})
        self.cookies = json.dumps(current_cookies)
        self.save()
    

    问题是,如果 chat 对象在两个不同的名称空间中检索,它们独立更新其Cookie,每一个都覆盖另一个的结果。

    例子:

    import django
    django.setup()
    
    from bots.models import Chat
    
    # Let's clean all the cookies beforehand 
    c = Chat.objects.get(pk=43265)
    c.cookies = None
    c.save()
    
    def outer_namespace():
        chat = Chat.objects.get(pk=43265)
    
        # here chat.cookies are empty
        inner_namespace()
        # Now we are supposed to have inner cookie here - right? Let's set another one.
    
        chat.set_cookie('outer namespace cookie', '1')
    
        # Let's retrieve the model again and see
        print(Chat.objects.get(pk=43265).cookies)
    
    
    def inner_namespace():
        inner_chat = Chat.objects.get(pk=43265)
        inner_chat.set_cookie('inner namespace cookie', '2')
    
    
    outer_namespace()
    

    如果我运行这个,我会得到:

    >>> {"outer namespace cookie": "1"}
    >>> # we lost one of the cookies!
    

    如何避免这种情况? 我提出的唯一解决方案是重新检索 闲聊 对象位于其自身的中间 set_cookies 方法但这看起来很笨拙。

    def set_cookie(self, key, value):
        cookies = self.__class__.objects.get(pk=self.pk).cookies
        #
        # ... rest of the method stays the same
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   e4c5    8 年前

    这是另一个典型的例子,说明了为什么应该始终规范化数据库。理想的结构应该是为聊天Cookie提供另一个模型

    class Cookie(models.Model):
        name = models.CharField()
        value = models.CharField()
        chat = models.ForeignKey(Chat)
    

    现在,您可以使用 .update 方法在queryset上执行。在您自己的线程或其他线程中设置。在每次保存之前,您不必一直重新读取数据。

    如果由于某些令人信服的原因,您无法将您的设计转换为正确的设计,您至少应该投资使用JsonField来创建Cookie。JSONField目前仅适用于postgresql,但其他数据库也有第三方插件。