django-fsm:不提出异常的权限

时间:2017-06-17 01:33:29

标签: django django-fsm

我在django-fsm(有限状态机)中有源和目标基于规则的转换装饰器。现在我正在尝试添加权限处理。这似乎很简单,但似乎无论我做什么,都会执行转换,无论用户是否拥有权限。我已尝试使用Django权限字符串,并且根据文档我尝试使用lambda。我已经尝试了所有这些:

@transition(field=state, source='prog', target='appr', permission='claims.change_claim')

@transition(field=state, source='prog', target='appr', permission=lambda instance, user: not user.has_perm('claims.change_claim'),)

并且,作为一个仔细检查,因为permission应该响应任何可调用的返回True / False,只需:

@transition(field=state, source='prog', target='appr', permission=False)
def approve(self):

在访问转换时,为所有用户提出TransitionNotAllowed。但是nope - 即使没有权限的基本用户仍然可以执行转换(claim.approve())。

要证明我的权限字符串是正确的:

print(has_transition_perm(claim.approve, request.user))

打印错误。我正在进行如下验证(适用于源/目标):

class ClaimEditForm(forms.ModelForm):
    '''
    Some users can transition claims through allowable states
    '''

    def clean_state(self):
        state = self.cleaned_data['state']
        if state == 'appr':
            try:
                self.instance.approve()
            except TransitionNotAllowed:
                raise forms.ValidationError("Claim could not be approved")
        return state

    class Meta:
        model = Claim
        fields = (
            'state',
        )

并且视图处理程序是标准:

if request.method == "POST":
    claim_edit_form = ClaimEditForm(request.POST, instance=claim)
    if claim_edit_form.is_valid():  # Validate transition rules

我错过了什么?感谢。

2 个答案:

答案 0 :(得分:0)

你应该真正阅读文档。

permissions documentation

答案 1 :(得分:-1)

问题是,permission属性的验证与源/目标验证器的验证方式不同。您必须在代码中的其他位置评估装饰器中建立的权限,而不是装饰器引发错误。因此,要从表单执行权限验证,您需要传入用户对象,以init形式接收用户,然后与has_transition_perm的结果进行比较。所以这有效:

# model
@transition(field=state, source='prog', target='appr', permission='claims.change_claim')
def approve(self):
....

# view
if request.method == "POST":
    claim_edit_form = ClaimEditForm(request.user, request.POST, instance=claim)
        ....

# form
from django_fsm import has_transition_perm

class ClaimEditForm(forms.ModelForm):
    '''
    Some users can transition claims through allowable states
    (see permission property on claim.approve() decorator)
    '''

    def __init__(self, user, *args, **kwargs):
        # We need to pass the user into the form to validate permissions
        self.user = user
        super(ClaimEditForm, self).__init__(*args, **kwargs)

    def clean_state(self):
        state = self.cleaned_data['state']
        if state == 'appr':
            if not has_transition_perm(self.instance.approve, self.user):
                raise forms.ValidationError("You do not have permission for this transition")