web-dev-qa-db-fra.com

Comment stocker un dictionnaire dans un champ de modèle de base de données Django

J'ai besoin d'enregistrer un dictionnaire dans le champ d'un modèle. Comment je fais ça?

Par exemple, j'ai ce code:

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()

Qu'est-ce que j'écris pour "bill_products =" afin qu'il enregistre des produits aléatoires, de mon modèle de produit à cette facture?

Voici la description du modèle du projet de loi:

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

Et aussi la description du modèle du produit:

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

S'il y a autre chose que je devrais ajouter, laissez simplement un commentaire. Merci!

25
Radu Gheorghiu

La chose la plus propre à faire serait probablement de créer une autre table "Produits" et d'avoir une relation plusieurs-à-plusieurs. (Voir ici: https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships . Dans les documents, ils utilisent l'exemple d'une pizza ayant de nombreuses garnitures.)

L'autre option serait de sérialiser vos produits bill_product. Dans ce cas, vous feriez quelque chose comme:

bill_products = json.dumps([Rand_products])

Ce serait en dehors de la boucle for (bien que, dans votre exemple ci-dessus, Rand_products ne soit qu'une seule valeur, vous devrez donc corriger cela).

6
gdw2

Je viens de découvrir le paquet Django-jsonfield , qui

est un champ Django réutilisable qui vous permet de stocker du JSON validé dans votre modèle.

Ressemble à une option viable pour réaliser ce que vous voulez.

21
ramiro

Une façon pratique de stocker une représentation JSON dans un modèle consiste à utiliser un type de champ personnalisé:

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)

J'ai enregistré ce utils/fields.py et dans mon modèle from utils.fields import JSONField. Il y a beaucoup plus de goodies dans l'application Django-ennuyeux , d'où vient cet extrait.

10
Tony Abou-Assaleh

L'utilisation d'un type de champ personnalisé est ma solution préférée - je préfère avoir quelques lignes de code personnalisé que de prendre en charge une bibliothèque tierce entière pour un seul type de champ. Tony Abou-Assaleh a une excellente solution, mais ne fonctionnera pas pour les nouvelles versions de Django.

Il est vérifié que cela fonctionne avec 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
10
Rico

Vous pouvez utiliser la sérialisation/désérialisation à partir du module de décapage:

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

3

Si postgres est votre backend, considérez le champ hstore qui a un support natif de Django

3
wjin

Je pense que je créerais le champ en tant que models.CharField () puis encoderais le dictionnaire en tant que chaîne JSON et enregistrerais cette chaîne dans la base de données. Ensuite, vous pouvez décoder la chaîne JSON dans un dictionnaire lorsque vous la lisez.

2
brian buck

Si vous utilisez PostGres, vous pouvez le stocker dans le champ JSON pris en charge nativement: https://docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/#jsonfield

Sinon, je recommanderais la réponse @ramiro avec une bibliothèque tierce https://stackoverflow.com/a/16437627/803174

1
Kangur