Question

Je dois stocker des données dans un modèle Django. Ces données ne correspondent pas à toutes les instances du modèle.

Au début, j’ai pensé à sous-classer le modèle, mais j’essaie de garder l’application souple. Si j’utilise des sous-classes, j’ai besoin de créer une classe entière chaque fois que j’ai besoin d’un nouveau type d’objet, ce qui ne sert à rien. Je vais aussi finir avec beaucoup de sous-classes uniquement pour stocker une paire de champs supplémentaires.

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

Des indices?

Était-ce utile?

La solution

Si vous recherchez un dictionnaire contenant des données arbitraires, vous pouvez probablement utiliser une configuration à deux niveaux avec un modèle qui est un conteneur et un autre modèle qui est une paire clé-valeur. Vous créez une instance du conteneur, créez chacune des instances clé-valeur et associez le jeu d'instances clé-valeur à l'instance de 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 beau, mais cela vous permettra d'accéder aux bases du dictionnaire à l'aide de la base de données, alors qu'une solution pickle / serialize ne le fera pas.

Autres conseils

Si vous n'avez pas besoin d'interroger ces données supplémentaires, vous pouvez les stocker sous forme de dictionnaire sérialisé. Utilisez repr pour transformer le dictionnaire en chaîne et eval pour reconvertir la chaîne en dictionnaire. Veillez à ce qu’il n’y ait pas de données utilisateur dans le dictionnaire ou utilisez une implémentation de safe_eval.

Je suis arrivé à ce message par le 4ème résultat de Google sur "objet magasin Django"

.

Un peu en retard, mais django-picklefield me semble une bonne solution.

Exemple de doc:

Pour l'utiliser, définissez simplement un champ dans votre modèle:

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

et attribuez ce que vous voulez (tant que c'est décelable) au champ:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()

Une autre solution simple 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()

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

Si vous avez toujours besoin de stocker des dictionnaires, la meilleure approche est de loin la classe PickleField décrite dans le nouveau livre de Marty Alchin, Pro Django . Cette méthode utilise les propriétés de la classe Python pour choisir / annuler un objet python, uniquement à la demande, stocké dans un champ de modèle.

Les bases de cette approche consistent à utiliser le contibute_to_class pour ajouter dynamiquement un nouveau champ à votre modèle et utilise getattr / setattr pour effectuer la sérialisation à la demande.

L’un des rares exemples en ligne similaires est cette définition d’un JSONField .

Je ne suis pas tout à fait sûr de la nature du problème que vous essayez de résoudre, mais cela ressemble étrangement à La table BigTable de Google App Engine .

Expandos vous permet de spécifier et de stocker des champs supplémentaires sur une instance d'objet sauvegardé par une base de données au moment de l'exécution. Pour citer les documents:

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 Python et le framework Django. Cela vaut peut-être la peine d’étudier si c’est le meilleur moyen d’exprimer vos modèles.

Les modèles de base de données relationnelle traditionnels n’offrent pas ce type de souplesse d’ajout de colonnes. Si vos types de données sont suffisamment simples, vous pouvez rompre avec la philosophie traditionnelle du SGBDR et pirater les valeurs en une seule colonne via la sérialisation en tant que @ Ned Batchelder propose; Cependant, si vous devez utiliser un SGBDR, l'héritage des modèles Django est probablement la solution. Notamment, il créera un un one-to -une clé étrangère pour chaque niveau de dérivation.

Je conviens que vous devez vous abstenir de regrouper des données autrement structurées dans une seule colonne. Mais si vous devez le faire, Django a un XMLField . incorporer.

Des JSONField sont également disponibles aux extraits Django.

Étant "différent de toutes les instances du modèle" Cela me semble être un bon accord pour une base de données "sans schéma". CouchDB est l'enfant à l'origine de cette approche et vous pouvez envisager de le prendre en compte.

Dans un projet, j'ai déplacé plusieurs tables qui ne jouaient jamais très bien avec l'ORM de Django vers CouchDB et j'en suis assez content. J'utilise couchdb-python sans aucun module CouchDB spécifique à Django. Vous trouverez une description du modèle de données ici . Le mouvement de cinq "modèles" dans Django à 3 " modèles " dans Django et une base de données CouchDB " en fait légèrement réduit le nombre total de lignes de code dans mon application.

Cette question est ancienne, mais j’avais le même problème, je m’étais terminée ici et la réponse choisie ne pouvait plus résoudre mon problème.

Si vous souhaitez stocker des dictionnaires dans Django ou dans Api REST, soit comme objets dans votre front-end, 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.

Lorsque vous enregistrez les données dans votre API, utilisez json.dump () méthode pour pouvoir le stocker dans un format json approprié, comme décrit dans cette question .

Si vous utilisez cette structure, vos données seront déjà au format json approprié pour être appelées au serveur frontal avec JSON.parse () dans votre appel ajax (ou autre).

Réfléchissez-y et trouvez les points communs de chaque ensemble de données ... puis définissez votre modèle. Cela peut nécessiter 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 lorsqu'elles ont un sens.

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

Django-Geo inclut un " DictionaryField " vous pourriez trouver 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 toutes les données, utilisez une approche dénormalisée pour éviter les requêtes supplémentaires. Les paramètres utilisateur sont un très bon exemple!

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

J'utilise un champ de texte et json.loads () / json.dumps ()

models.py

import json
from django.db import models

class Item(models.Model):
    data = models.TextField(blank=True, null=True, default='{}')

    def save(self, *args, **kwargs):
        ## load the current string and
        ## convert string to python dictionary
        data_dict = json.loads(self.data)

        ## do something with the dictionary
        for something in somethings:
            data_dict[something] = some_function(something)

        ## if it is empty, save it back to a '{}' string,
        ## if it is not empty, convert the dictionary back to a json string
        if not data_dict:
            self.data = '{}'
        else:
            self.data = json.dumps(data_dict)


        super(Item, self).save(*args, **kwargs)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top