允许Django自定义字段在父mod上触发save()

2024-09-30 02:20:38 发布

您现在位置:Python中文网/ 问答频道 /正文

问题:

我有一个自定义字段类型,它偶尔需要更新属性并将自己重新保存到数据库中。我正在尝试确定是否可以在字段层强制执行,而不必在模型层实现。你知道吗

动机:

我查了一下django.contrib.auth公司handles workfactor upgrades,它将此任务降级到拥有加密字段的模型。你知道吗

我更喜欢在字段级别实现这个功能,这样自定义字段类型就可以在各种应用程序的许多模型上实现。你知道吗

示例:

我有一个自定义字段类型SecretField,它将类型Secret存储为模型属性。通常,Secret包含加密数据,密钥是用户提供的密码的PBKDF2散列。根据需要进行解密。你知道吗

假设这是通过以下大纲实现的:

from django.utils.six import with_metaclass
from django.db import models

class BuriedTreasure(models.Model):
    location = SecretField()

class SecretField(with_metaclass(models.SubfieldBase, models.Field)):
    #... (a bunch of logic) ...

class Secret(object):
    def __init__(self, ciphertext, salt, workfactor):
        self.ciphertext = ciphertext
        self.salt = salt
        self.workfactor = workfactor

    @classmethod
    def from_ciphertext(cls, ciphertext, salt, workfactor):
        """Generate a Secret object for later decyption."""
        return cls(ciphertext, salt, workfactor)

    def to_plaintext(self, password):
        """Decrypt ciphertext and return plaintext."""
        #... (decrypt ciphertext using salt & workfactor) ...
        return plaintext

bt = BuriedTreasure.objects.get(pk=1)
print bt.location.to_plaintext('mypassword')

调用bt.location.to_plaintext()时,我想检查bt.location.workfactor是否不再满足的Django需求(可能由于Django升级而发生了更改)。如果不是,我应该重新加密Secret并发出bt.save(update_fields=['location'])以升级机密的保护。此解决方案将允许所有SecretField属性在解密时自动升级其workfactors。你知道吗

我想实施的是:

我想通过以下方式实现这一点:

class Secret(object):
    def __init__(self, ciphertext, salt, workfactor, plaintext=None, password=None):
        self.ciphertext = ciphertext
        self.salt = salt
        self.workfactor = workfactor
        #...

    @classmethod
    def from_ciphertext(cls, ciphertext, salt, workfactor):
        """Generate a Secret object for later decyption."""
        return cls(ciphertext, salt, workfactor)

    def from_plaintext(cls, plaintext, password):
        """Generate a Secret object from plaintext and password."""
        return cls(plaintext=plaintext, password=password)

    def to_plaintext(self, password):
        """Decrypt ciphertext and return plaintext."""
        #... (decrypt ciphertext using salt & workfactor) ...

        if self.workfactor < DJANGO_THRESHOLD:
            new_secret = Secret.from_plaintext(plaintext, password)
            #Update parent model's field with new_secret
            #Save parent model's field to database
        return plaintext

我被困的地方

目前,我不知道如何访问Secret所属的模型实例。即使我在SecretField.from_db_value()内用Secret实例注册SecretField,我也找不到访问父模型的方法。这是可能的,还是有更好的方法来实现我的目标(也许通过在一个通用的、可继承的模型上实现)?你知道吗


Tags: from模型selfsecretreturnobjectdeflocation

热门问题