当前位置:  开发笔记 > 编程语言 > 正文

在Django中锁定对象的最简单方法是什么

如何解决《在Django中锁定对象的最简单方法是什么》经验,为你挑选了2个好方法。

当某个其他用户在update_object视图中处于活动状态时,我想在用户尝试删除对象时引发错误.我觉得需要某种类似互斥锁的机制.你有什么建议吗?



1> David Berger..:

所以,有一些方法可以做你所要求的.但是其中很多都不是独立于实现的:你可以使用锁或rlocks,但它们实际上只能在100%线程服务器上工作,而在fork/pre-fork实现中可能根本不工作.

这或多或少意味着锁定实现将取决于您.两个想法:

    .lock 文件系统上的文件

    locked 模型类中的属性

在这两种情况下,您都必须在更新时手动设置锁定对象,并在删除时检查它.尝试类似的东西:

def safe_update(request,model,id):
    obj = model.objects.get(id)
    if obj.locked:
        raise SimultaneousUpdateError #Define this somewhere
    else:
        obj.lock()
        return update_object(request,model,id)

# In models file
class SomeModel(models.Model):
    locked = models.BooleanField(default = False)
    def lock(self):
        self.locked = True
        super(models.Model,self).save()
    def save(self):
        # overriding save because you want to use generic views
        # probably not the best idea to rework model code to accomodate view shortcuts
        # but I like to give examples.
        self.locked = False
        # THIS CREATES A DIFFERENT CRITICAL REGION!
        super(models.Model,self).save()

这确实是一个笨拙的实现,你必须清理.您可能对创建不同的关键区域这一事实感到不舒服,但如果您将数据库用作实现而不使实现变得更复杂,我不会看到您将如何做得更好.(一种选择是使锁完全独立的对象.然后你可以在调用save()方法后更新它们.但是我不想编码那么.)如果你真的想使用基于文件的锁定系统,这也将解决问题.如果你是数据库命中偏执狂,这可能适合你.就像是:

class FileLock(object):
    def __get__(self,obj):
        return os.access(obj.__class__+"_"+obj.id+".lock",os.F_OK)
    def __set__(self,obj,value):
        if not isinstance(value,bool):
            raise AttributeError
        if value:
            f = open(obj.__class__+"_"+obj.id+".lock")
            f.close()
        else:
            os.remove(obj.__class__+"_"+obj.id+".lock")
    def __delete__(self,obj):
        raise AttributeError

 class SomeModel(models.Model):
     locked = FileLock()
     def save(self):
         super(models.Model,self).save()
         self.locked = False

无论如何,也许有一些方法可以根据您的口味混合和匹配这些建议?



2> Edward D'Sou..:

由于添加了select_for_update,只要数据库支持,就可以通过一种简单的方法来获取对象的锁定.根据Django文档,postgresql,oracle和mysql至少支持它.

示例代码:

import time

from django.contrib.auth import get_user_model
from django.db import transaction


User = get_user_model()

target_user_pk = User.objects.all()[0].pk


with transaction.atomic():
    print "Acquiring lock..."
    to_lock = User.objects.filter(pk=target_user_pk).select_for_update()
    # Important! Queryset evaluation required to actually acquire the lock.
    locked = to_lock[0]
    print locked

    while True:
        print "sleeping {}".format(time.time())
        time.sleep(5)

推荐阅读
跟我搞对象吧
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有