Django模型能使用MySQL函数吗?
有没有办法让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
,否则这些方法就不会被调用。