Comment stocker un dictionnaire sur un Modèle Django?

j'ai besoin de stocker des données dans un modèle Django. Ces données ne sont pas égaux à toutes les instances du modèle.

au début, j'ai pensé à sous-classer le modèle, mais j'essaie de garder l'application flexible. Si j'utilise des sous-classes, je vais avoir besoin de créer une classe entière chaque fois que j'ai besoin d'un nouveau type d'objet, et ce n'est pas bon. Je vais aussi finir avec beaucoup de sous-classes seulement pour stocker une paire de champs supplémentaires.

je pense vraiment qu'un dictionnaire être la meilleure approche, mais il n'y a rien dans la documentation Django sur le stockage d'un dictionnaire dans un modèle Django (ou Je ne peux pas le trouver).

des indices?

49
demandé sur Paul D. Waite 2008-12-31 06:18:15

12 réponses

si c'est vraiment un dictionnaire comme les données arbitraires que vous recherchez, vous pouvez probablement utiliser une configuration à deux niveaux avec un modèle qui est un conteneur et un autre modèle qui est des paires de valeurs-clés. Vous devez créer une instance du conteneur, créer chacune des instances de valeurs clés, et associer l'ensemble des instances de valeurs clés avec l'instance du conteneur. Quelque chose comme:

class Dicty(models.Model):
    name      = models.CharField(max_length=50)

class KeyVal(models.Model):
    container = models.ForeignKey(Dicty, db_index=True)
    key       = models.CharField(max_length=240, db_index=True)
    value     = models.CharField(max_length=240, db_index=True)

ce n'est pas joli, mais il vous permettra d'accéder/rechercher les entrailles du dictionnaire en utilisant le DB alors qu'une solution de pickle/serialize ne le sera pas.

34
répondu Parand 2008-12-31 08:19:28

si vous n'avez pas besoin d'interroger par ces données supplémentaires, alors vous pouvez le stocker comme un dictionnaire sérialisé. Utilisez repr pour transformer le dictionnaire en une chaîne, et eval pour transformer la chaîne en un dictionnaire. Faites attention avec eval qu'il n'y a pas de données utilisateur dans le dictionnaire, ou utilisez une implémentation safe_eval.

14
répondu Ned Batchelder 2008-12-31 03:39:18

je suis venu à ce poste par google 4ème résultat pour "django objet de banque"

un peu en retard, mais django-picklefield semble être une bonne solution pour moi.

exemple tiré du doc:

À utiliser, il suffit de définir un champ dans votre modèle:

>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>>     args = PickledObjectField()

et assignez ce que vous voulez (tant que c'est facile) au champ:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
11
répondu Stéphane 2011-09-19 10:10:04

une autre solution propre et rapide peut être trouvée ici: https://github.com/bradjasper/django-jsonfield

pour plus de commodité, j'ai copié les instructions simples.

Installer

pip install jsonfield

Utilisation

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()
11
répondu odedfos 2013-07-31 12:50:28

comme Ned a répondu, Vous ne pourrez pas interroger "certaines données" si vous utilisez l'approche du dictionnaire.

si vous avez encore besoin de stocker des dictionnaires, alors la meilleure approche, de loin, est la classe PickleField documentée dans le nouveau livre de Marty Alchin Pro Django . Cette méthode utilise les propriétés de la classe Python pour sélectionner/décompresser un objet python, uniquement sur demande, qui est stocké dans un champ model.

Les bases de cette approche est d'utiliser la méthode contibute_to_class de django pour ajouter dynamiquement un nouveau champ à votre modèle et utilise getattr/setattr pour faire la sérialisation à la demande.

un des rares exemples en ligne que j'ai pu trouver qui est similaire est cette définition d'un JSONField .

7
répondu Van Gale 2008-12-31 07:44:46

Je ne suis pas sûr exactement de la nature du problème que vous essayez de résoudre, mais il semble curieusement similaire à Google App Engine Bigtable Expando .

Les Expandos

vous permettent de spécifier et de stocker des champs supplémentaires sur une instance d'objet appuyée sur une base de données à l'exécution. Pour citer les docs:

import datetime
from google.appengine.ext import db

class Song(db.Expando):
  title = db.StringProperty()

crazy = Song(title='Crazy like a diamond',
             author='Lucy Sky',
             publish_date='yesterday',
             rating=5.0)

crazy.last_minute_note=db.Text('Get a train to the station.')

Google App Engine prend actuellement en charge à la fois Python et le cadre Django. Peut-être intéressant de regarder dans si c'est la meilleure façon d'exprimer vos modèles.

les modèles de base de données relationnelles traditionnelles n'ont pas ce genre de flexibilité d'ajout de colonne. Si vos types de données sont assez simples, vous pouvez rompre avec la philosophie traditionnelle RDBMS et hacker les valeurs en une seule colonne via la sérialisation comme @ned Batchelder propose; cependant, si vous avez pour utiliser un RDBMS, L'héritage du modèle Django est probablement la voie à suivre. Notamment, il sera créer une relation de clé étrangère de un à un pour chaque niveau de dérivation.

5
répondu cdleary 2017-05-23 11:54:50

je suis d'accord que vous devez vous abstenir de bourrer des données autrement structurées dans une seule colonne. Mais si vous devez faire cela, Django a un XMLField build-in.

il y a aussi JSONField chez Django snipplets.

3
répondu muhuk 2009-05-13 18:05:44

étant " pas égal à toutes les instances du modèle "sonne pour moi comme une bonne correspondance pour une"base de données sans schéma". CouchDB est l'enfant modèle pour cette approche et vous pourriez considérer cela.

dans un projet j'ai déplacé plusieurs tables qui ne jouaient jamais très bien avec L'ORM Django à CouchDB et je suis très heureux avec cela. J'utilise couchdb-python sans aucun des modules CouchDB spécifiques à Django. Description le modèle de données peut être trouvé ici . Le passage de cinq "modèles" à Django à trois "modèles" à Django et à une "base de données" CouchDB a en fait légèrement réduit le nombre total de lignes de code dans mon application.

3
répondu max 2014-08-09 11:34:37

réfléchissez-y et trouvez les points communs de chaque ensemble de données... définissez ensuite votre modèle. Elle peut exiger l'utilisation de sous-classes ou non. Les clés étrangères représentant des points communs ne doivent pas être évitées, mais encouragées quand elles ont du sens.

coller des données aléatoires dans une table SQL n'est pas intelligent, à moins que ce soit vraiment des données non relationnelles. Si c'est le cas, définissez votre problème et nous pourrons peut-être vous aider.

2
répondu Daniel Naab 2008-12-31 05:54:12

Django-Geo comprend un "DictionaryField" peut vous être utile:

http://code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49

en général, si vous n'avez pas besoin d'interroger à travers les données Utiliser une approche dénormalisée pour éviter les requêtes supplémentaires. Les paramètres utilisateur en sont un bon exemple!

2
répondu jb. 2009-05-13 16:50:37

si vous utilisez Postgres, vous pouvez utiliser un champ hstore: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield .

1
répondu Scott Stafford 2016-08-30 19:36:59

cette question Est ancienne, mais j'avais le même problème, s'est terminée ici et la réponse choisie ne pouvait plus résoudre mon problème.

si vous voulez stocker des dictionnaires dans L'Api Django ou REST, soit pour être utilisé comme objets dans votre face avant, soit parce que vos données n'auront pas nécessairement la même structure, la solution que j'ai utilisée peut vous aider.

lors de la sauvegarde des données dans votre API, utilisez json.dump () méthode pour pouvoir stocker il dans un format JSON approprié, comme décrit dans cette question .

si vous utilisez cette structure, vos données seront déjà dans le format JSON approprié pour être appelé à l'avant avec JSON.parse() dans votre ajax (ou autre).

0
répondu Lucas Colzani 2018-08-02 08:56:20