Как сохранить словарь в поле модели базы данных Django - PullRequest
24 голосов
/ 13 марта 2012

Мне нужно сохранить словарь в поле модели.Как мне это сделать?

Например, у меня есть этот код:

def create_random_bill(self):
    name_chars = re.compile("[a-zA-Z0-9 -_]")
    bill_name = "".join(random.choice(name_chars for x in range(10)))
    rand_products = random.randint(1,100)
    for x in rand_products:
        bill_products = 
    new_bill = Bill.new(name=bill_name, date=datetime.date, products=bill_products)
    new_bill.save()

Что я пишу для "bill_products =", поэтому он сохраняет некоторые случайные продукты, от моей модели продукта до этойbill?

Это описание модели счета:

class Bill(models.Model):
    name = models.CharField(max_length=255)
    date = models.DateTimeField(auto_now_add=True)
    products = models.ManyToManyField(Product, related_name="bills")

А также описание модели продукта:

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.IntegerField()

Если есть что-то еще, что я должен добавить, просто оставьтекомментарий.Спасибо!

Ответы [ 7 ]

20 голосов
/ 08 мая 2013

Я только что обнаружил пакет django-jsonfield , который

- это повторно используемое поле Django, которое позволяет вам сохранять проверенный JSON в вашей модели.

Похоже, жизнеспособный вариант для достижения того, что вы хотите.

11 голосов
/ 14 марта 2012

Один удобный способ сохранить представление JSON в модели - это использовать пользовательский тип поля:

class JSONField(models.TextField):
    """
    JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly.
    Django snippet #1478

    example:
        class Page(models.Model):
            data = JSONField(blank=True, null=True)


        page = Page.objects.get(pk=5)
        page.data = {'title': 'test', 'type': 3}
        page.save()
    """

    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, basestring):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def get_db_prep_save(self, value, *args, **kwargs):
        if value == "":
            return None
        if isinstance(value, dict):
            value = json.dumps(value, cls=DjangoJSONEncoder)
        return super(JSONField, self).get_db_prep_save(value, *args, **kwargs)

Я сохранил этот файл utils / fields.py и в моей модели from utils.fields import JSONField.В приложении django-раздражает есть еще много вкусностей, откуда и появился этот фрагмент.

9 голосов
/ 25 января 2017

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

Это проверено для работы с Django 1.10.4

import json

from django.db import models
from django.core.serializers.json import DjangoJSONEncoder


class JSONField(models.TextField):
    """
    JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly.
    Django snippet #1478

    example:
        class Page(models.Model):
            data = JSONField(blank=True, null=True)


        page = Page.objects.get(pk=5)
        page.data = {'title': 'test', 'type': 3}
        page.save()
    """

    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, str):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def from_db_value(self, value, *args):
        return self.to_python(value)

    def get_db_prep_save(self, value, *args, **kwargs):
        if value == "":
            return None
        if isinstance(value, dict):
            value = json.dumps(value, cls=DjangoJSONEncoder)
        return value
6 голосов
/ 13 марта 2012

Вероятно, самое чистое, что нужно сделать, - это создать еще одну таблицу "Продукты" и иметь отношения "многие ко многим". (См. Здесь: https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships. В документах они используют пример пиццы с большим количеством начинки.)

Другим вариантом будет сериализация ваших bill_products. В этом случае вы бы сделали что-то вроде:

bill_products = json.dumps([rand_products])

Это будет за пределами цикла for (хотя в приведенном выше примере rand_products является только одним значением, поэтому вам нужно это исправить).

3 голосов
/ 01 января 2015

Если postgres - ваш бэкэнд, рассмотрите поле hstore, которое имеет встроенную поддержку от django

3 голосов
/ 23 декабря 2013

Вы можете использовать сериализацию / десериализацию из модуля pickle:

http://docs.python.org/library/pickle.html

2 голосов
/ 13 марта 2012

Я думаю, что я хотел бы создать поле как models.CharField (), а затем закодировать словарь в виде строки JSON и сохранить эту строку в базе данных.Затем вы можете декодировать строку JSON обратно в словарь при ее чтении.

...