Могут ли модели Django использовать функции MySQL?

Есть ли способ заставить модели Django передавать поле в функцию MySQL каждый раз, когда данные модели считываются или загружаются? Чтобы уточнить, что я имею в виду в SQL, я хочу, чтобы модель Django создала что-то вроде следующего:

При загрузке модели: SELECT AES_DECRYPT (имя поля, пароль) FROM tablename

При сохранении модели: INSERT INTO tablename VALUES (AES_ENCRYPT (userinput, password))

  • Django - создание пользователя с пользовательской моделью приводит к внутренней ошибке
  • sudo python запускает старую версию python
  • Запуск ярлыка под окнами
  • conda install python = 3.6 UnsatisfiableError
  • HOGDescriptor с видео для распознавания объектов
  • Возвращение нескольких значений из pandas применяется к DataFrame
  • Расчет времени рассвета и захода солнца с использованием PyEphem
  • dump csv из sqlalchemy
  • 6 Solutions collect form web for “Могут ли модели Django использовать функции MySQL?”

    Я бы определил собственный modelfield для столбца, который вы хотите зашифровать / дешифровать. Переопределите метод to_python для запуска дешифрования при загрузке модели и get_db_prep_value для запуска шифрования при сохранении.

    Не забудьте установить метакласс поля в models.SubfieldBase иначе эти методы не будут вызываться.

    Вместо загрузки модели вы можете создать свойство на своей модели, и когда доступ к ресурсу будет доступен, он может прочитать базу данных:

     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 , и первый доступ будет извлекать дешифрование из базы данных, удерживая ее для последующего доступа.

    Это также имеет то преимущество, что если какой-либо из ваших кодов не используется для расшифровки, этого не произойдет.

    Вот рабочее решение, частично основанное на ( 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) 

    Это определенно хакерский, но, похоже, Django не позволит вам сделать это иначе. Также стоит отметить, что to_python будет вызываться каждый раз, когда вы изменяете значение в python в дополнение к тому, когда оно будет сначала загружено.

     from django.db import connection, models import re class EncryptedField(models.TextField): __metaclass__ = models.SubfieldBase def to_python(self, value): if not re.match('^*some pattern here*$', value): cursor = connection.cursor() cursor.execute('SELECT AES_DECRYPT(%s, %s)', [value, settings.SECRET_KEY]) return cursor.fetchone()[0] return value def get_db_prep_value(self, value): cursor = connection.cursor() cursor.execute('SELECT AES_ENCRYPT(%s, %s)', [value, settings.SECRET_KEY]) return cursor.fetchone()[0] class Encrypt(models.Model): encrypted = EncryptedField(max_length = 32) 

    После глубокого поиска в реализации Django ORM,

    Я обнаружил, что это можно решить примерно так:

     class EncryptedField(models.BinaryField): @staticmethod def _pad(value): return value + (AES.block_size - len(value) % AES.block_size) * b('\x00') def _encrypt(self, data): if not data: return None return self.cipher.encrypt(self._pad(data.encode('utf8'))) def _decrypt(self, data): if not data: return None return self.cipher.decrypt(force_bytes(data)).rstrip(b'\x00').decode('utf8') @property def cipher(self): return AES.new(KEY, mode=AES.MODE_CBC, IV=self._iv) def get_db_prep_value(self, value, connection, prepared=False): if value is not None: value = self._encrypt(value) if value: value = binascii.hexlify(value) return value def get_placeholder(self, value, compiler, connection): return 'unhex(%s)' 

    Используя сигналы Django, вы можете делать что-либо, когда экземпляр модели сохраняется, но насколько я знаю, вы не можете ничего запускать при чтении.

    EDIT: Мой плохой, кажется, что вы можете делать вещи при инициализации экземпляра модели.

    Python - лучший язык программирования в мире.