【问题标题】:Django: how to wrap DB function on top of the field while querying records from that model and inserting using Django Custom Model Field?Django:如何在从该模型查询记录并使用 Django 自定义模型字段插入时在字段顶部包装 DB 函数?
【发布时间】:2020-05-11 11:56:29
【问题描述】:

我在模型中有一个文本字段。其中包含该字段中的加密字符串。另外,我在数据库中有 2 个函数来加密和解密。因此,我想将这些 DB 函数包装在该字段之上,并将加密字符串保存在 DB 中,并且在检索解密函数时应将其包装在该字段上,并且对象应该在该属性中具有解密字符串。

我正在考虑在 Django 中使用自定义字段。请告诉我该怎么做?

class User(models.model):
    name = models.CharField()
    age = models.IntegerField()
    email = models.TextField()

例如,让我们以电子邮件字段为例,我希望在该文本字段中有一个加密字符串。

我们来看看数据库函数 encrypt_email、decrypt_email

当我运行以下命令时

user_objects= User.objects.filter(age__gt = 20)

它应该像下面这样运行查询

SELECT *, decrypt_email(email) as email FROM users where age > 20;

在插入时也应该按如下方式运行查询

INSERT INTO users (name, age, email) VALUES ('Rafiu', 25, encrypt_email('abc@gmail.com'));

【问题讨论】:

  • 你能分享一些关于这个的代码吗?
  • @ruddra 更新了描述。

标签: django django-models


【解决方案1】:

我已经分析了Django框架并使用自定义模型字段实现了如下。

from django.db.models.expressions import Col
from django.db.models import Func, TextField, Value
from django.utils.functional import cached_property


class EncryptEmail(Func):
    def __init__(self, expression, **extra):
        super().__init__(
            expression,
            **extra
        )

    function = 'encrypt_email'
    template = "%(function)s(%(expressions)s)"


class CustomCol(Col):

    def as_sql(self, compiler, connection):
        qn = compiler.quote_name_unless_alias
        base_sql = "{alias}.{col}".format(alias=qn(self.alias), col=qn(self.target.column))
        sql_str = "{f_name}({n_name})".format(f_name='decrypt_email', n_name=base_sql)
        return sql_str, []


class EncryptedTextField(TextField):
    description = "Values Saved Encrypted and retrieved Decrypted"

    def pre_save(self, model_instance, add):
        setattr(model_instance, self.attname, EncryptEmail(Value(getattr(model_instance, self.attname))))
        return getattr(model_instance, self.attname)

    def select_format(self, compiler, sql, params):
        sql_str = "{n_name} as {rn_name}".format(n_name=sql, rn_name=self.attname)
        return sql_str, params

    def get_col(self, alias, output_field=None):
        if output_field is None:
            output_field = self
        if alias != self.model._meta.db_table or output_field != self:
            return CustomCol(alias, self, output_field)
        else:
            return self.cached_col

    @cached_property
    def cached_col(self):
        return CustomCol(self.model._meta.db_table, self)


class User(models.model):
    name = models.CharField()
    age = models.IntegerField()
    email = EncryptedTextField()

它按预期工作。

【讨论】:

    猜你喜欢
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-17
    • 2012-12-11
    • 2015-04-16
    • 2022-01-24
    • 2021-11-14
    相关资源
    最近更新 更多