Django模型能使用MySQL函数吗?

4 投票
6 回答
3905 浏览
提问于 2025-04-15 15:58

有没有办法让Django模型在每次读取或加载数据时,都把某个字段传给MySQL的一个函数?我想说的是,在SQL中,我希望Django模型能做出类似下面的操作:

在加载模型时:SELECT AES_DECRYPT(fieldname, password) FROM tablename

在保存模型时:INSERT INTO tablename VALUES (AES_ENCRYPT(userinput, password))

6 个回答

3

这里有一个可用的解决方案,部分内容参考了这个链接(http://www.djangosnippets.org/snippets/824/):

class Employee(models.Model):
   social_security_number = models.CharField(max_length=32)

   def _get_ssn(self):
       cursor = connection.cursor()
       cursor.execute("SELECT AES_DECRYPT(UNHEX(social_security_number), %s) as ssn FROM tablename WHERE id=%s", [settings.SECRET_KEY, self.id])
       return cursor.fetchone()[0]

   def _set_ssn(self, ssn_value):
       cursor = connection.cursor()
       cursor.execute("SELECT HEX(AES_ENCRYPT(%s, %s)) as ssn", [ssn_value, settings.SECRET_KEY])
       self.social_security_number = cursor.fetchone()[0]

   ssn = property(_get_ssn, _set_ssn)

这是运行结果:

>>> from foo.bar.models import Employee
>>> p=Employee.objects.create(ssn='123-45-6789')
>>> p.ssn
'123-45-6789'

mysql> select * from foo_employee;
+----+----------------------------------+
| id | social_security_number           |
+----+----------------------------------+
| 31 | 41DF2D946C9186BEF77DD3307B85CC8C |
+----+----------------------------------+
1 row in set (0.00 sec)
6

你可以在模型上创建一个属性,而不是在加载模型的时候就去读取数据。这样,当你访问这个属性的时候,它会去数据库读取数据:

def _get_foobar(self):
    if not hasattr(self, '_foobar'):

        cursor = connection.cursor()
        self._foobar = cursor.execute('SELECT AES_DECRYPT(fieldname, password) FROM tablename')[0]
    return self._foobar
foobar = property(_get_foobar)

现在在加载之后,你可以使用 mything.foobar,第一次访问的时候会从数据库中获取解密数据,并且会把这个数据保存起来,以便后续使用。

这样做还有个好处,就是如果你的某些代码不需要解密数据,它就不会去执行这个操作。

4

我会为你想要加密或解密的那一列定义一个自定义模型字段。重写to_python方法,这样在加载模型时就会进行解密;而重写get_db_prep_value方法,则是在保存时进行加密。

记得把这个字段的元类设置为models.SubfieldBase,否则这些方法就不会被调用。

撰写回答