У меня фактически была такая же потребность, и я написал настраиваемое поле базы данных для ее обработки. Просто сохраните следующее в модуле Python в вашем проекте (например, файл fields.py
в соответствующем приложении), а затем импортируйте и используйте его:
class JSONField(models.TextField):
"""Specialized text field that holds JSON in the database, which is
represented within Python as (usually) a dictionary."""
__metaclass__ = models.SubfieldBase
def __init__(self, blank=True, default='{}', help_text='Specialized text field that holds JSON in the database, which is represented within Python as (usually) a dictionary.', *args, **kwargs):
super(JSONField, self).__init__(*args, blank=blank, default=default, help_text=help_text, **kwargs)
def get_prep_value(self, value):
if type(value) in (str, unicode) and len(value) == 0:
value = None
return json.dumps(value)
def formfield(self, form_class=JSONFormField, **kwargs):
return super(JSONField, self).formfield(form_class=form_class, **kwargs)
def bound_data(self, data, initial):
return json.dumps(data)
def to_python(self, value):
# lists, dicts, ints, and booleans are clearly fine as is
if type(value) not in (str, unicode):
return value
# empty strings were intended to be null
if len(value) == 0:
return None
# NaN should become null; Python doesn't have a NaN value
if value == 'NaN':
return None
# try to tell the difference between a "normal" string
# and serialized JSON
if value not in ('true', 'false', 'null') and (value[0] not in ('{', '[', '"') or value[-1] not in ('}', ']', '"')):
return value
# okay, this is a JSON-serialized string
return json.loads(value)
Пара вещей. Во-первых, если вы используете Юг, вам нужно объяснить ему, как работает ваше настраиваемое поле:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], [r'^feedmagnet\.tools\.fields\.models\.JSONField'])
Во-вторых, хотя я проделал большую работу, чтобы убедиться, что это настраиваемое поле играет хорошо везде, например, аккуратно переходя между сериализованным форматом и Python. Есть одно место, где он не совсем работает должным образом, это когда он используется вместе с manage.py dumpdata
, где он объединяет Python в строку, а не выгружает его в JSON, а это не то, что вам нужно. Я обнаружил, что это незначительная проблема на практике.
Дополнительная документация по написанию пользовательских полей модели .
Я утверждаю, что это единственный лучший и наиболее очевидный способ сделать это. Обратите внимание, что я также предполагаю, что вам не нужно выполнять поиск на этих данных - например, вы будете получать записи на основе других критериев, и это будет сопровождаться этим. Если вам нужно выполнить поиск на основе чего-либо в вашем JSON, убедитесь, что это истинное поле SQL (и убедитесь, что оно проиндексировано!).