如何获取并发操作的django模型的锁定

时间:2017-12-26 18:52:21

标签: python django django-models django-forms

我正在尝试获取django模型中的锁定,例如,如果用户1正在编辑,则一旦用户1离开表单,用户2将禁用用户2将具有访问权限。 但仍然无法找到解决方案

my current model.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

这会引发错误django.core.management.base.SystemCheckError:SystemCheckError:系统检查发现了一些问题:

错误: :(admin.E108)'list_display [5]'的值是指'db_locked_by',它不是可调用的,'Mymodeladmin'的属性,或'user_admin.Mymodel'上的属性或方法。

from ripplr.middleware import get_current_user
from django.db import models
from django.contrib.auth.models import User
import datetime
import urllib2 


from django.http import request


# Create your models here.
#user_id=models.OneToOneField(User, primary_key=True)
class Mymodel(models.Model):
    id=models.IntegerField(primary_key=True,help_text="unique id for the run")
    job_name=models.CharField(max_length=20,help_text="JOB_NAME")
    number_of_runs=models.IntegerField(help_text="overall runs")
    run_time=models.DateField(auto_now_add=True)
    JOB_STATUS = (
        ('A', 'ACTIVE'),
        ('R', 'RUNNING'),
        ('F', 'FAILED'),
        ('IN', 'INACTIVE')
        )

    status= models.CharField(max_length=1, choices=JOB_STATUS, blank=True, default='A', help_text='SET JOB STATUS')
    lock_time=datetime.datetime.now()
    #db_locked_by =models.OneToOneField(User,null=True,blank=True)
    db_locked_by=get_current_user()
#


    def __str__(self):
        return '%s (%s)' % (self.id,self.job_name)

    def get_absolute_url(self):
        return reverse('Job-Detail', args=[str(self.job_name)])

class Meta:
    ordering=["-run_time"]

1 个答案:

答案 0 :(得分:0)

我认为你可以创建一些简单的锁机制。您可以向模型添加两个字段:lock_user和lock_dt。每次用户开始编辑时,都会将lock_user设置为user,将lock_dt设置为当前时间。编辑完成后,您只需清除字段。如果其他用户尝试编辑实例,则检查字段是否为空。您可以获得一些永久锁定文件的保护 - 您可以删除/忽略超过x分钟的每个锁。

虽然我不确定它是否是最新的,但您可以使用github上的django-locking库。

在下面您将找到一个如何锁定对象的示例,这样其他任何人都无法在Django admin中编辑同一个对象。 当用户开始编辑对象时,会有30分钟的锁定时间。其他用户不会看到表单按钮 - 他们会看到一条消息"对象被锁定"代替。 它基于覆盖ModelAdmin类和change_view模板的两种方法。

# models.py
from django.db import models
from django.contrib.auth.models import User
class Mymodel(models.Model):
    JOB_STATUS = (
        ('A', 'ACTIVE'),
        ('R', 'RUNNING'),
        ('F', 'FAILED'),
        ('IN', 'INACTIVE')
        )
    job_name = models.CharField(max_length=20)
    number_of_runs=models.IntegerField()
    run_time=models.DateField(auto_now_add=True)
    status= models.CharField(max_length=1, choices=JOB_STATUS, blank=True, default='A')
    locked_by = models.ForeignKey(User, null=True, blank=True)
    locked_dt = models.DateTimeField(null=True, blank=True)


# admin.py
from django.contrib import admin
from .models import MyModel
from django.utils import timezone
from datetime import timedelta

class MyModelAdmin(admin.ModelAdmin):
    # Make the fields with lock information read-only
    readonly_fields = ('locked_by', 'locked_dt')
    # Override the template with you own
    change_form_template = 'mymodel_change_form.html'

    def save_model(self, request, obj, form, change):
        # Release the lock when saving the object
        obj.locked_by = None
        obj.locked_dt = None
        super(MyModelAdmin, self).save_model(request, obj, form, change)

    def change_view(self, request, object_id=None, form_url='', extra_context=None):
        # Mark the object as locked when the user starts editing
        object = MyModel.objects.get(pk=object_id)
        if request.method == 'GET':
            # Set a new lock if there's no lock or the user set the lock or the lock was set more than 30m ago
            if object.locked_by is None or object.locked_by == request.user or \
                timezone.now() - object.locked_dt > timedelta(minutes=30):
                object.locked_by = request.user
                object.locked_dt = timezone.now()
                object.save()
            extra_context = extra_context or {}
            extra_context['is_locked'] = object.locked_by != request.user

        return super(MyModel, self).change_view(request, object_id, form_url, extra_context)


# templates/mymodel_change_form.html

{% extends "admin/change_form.html" %}
{% load admin_modify %}
{% block submit_buttons_bottom %}
{% if is_locked %}<strong>Object is locked</strong>
{% else %}{% submit_row %}{% endif %}
{% endblock %}