193 votes

Quel est le moyen le plus efficace de stocker une liste dans les modèles Django?

Actuellement, j'ai beaucoup d'objets python dans mon code semblable au suivant:

class MyClass():
  def __init__(self, name, friends):
      self.myName = name
      self.myFriends = [str(x) for x in friends]

Maintenant, je veux en faire un modèle Django, où l'auto.myName est une chaîne de caractères, et l'auto.myFriends est une liste de chaînes.

from django.db import models

class myDjangoModelClass():
    myName = models.CharField(max_length=64)
    myFriends = ??? # what goes here?

Depuis la liste de est une commune de la structure de données en python, j'ai attendu qu'il y ait un Django champ de modèle pour elle. Je sais que je peux utiliser un ManyToMany ou relation OneToMany, mais j'espérais pour éviter qu'supplémentaire d'indirection dans le code.

Edit:

J'ai ajouté cette question connexe, qui les gens peuvent trouver utile.

152voto

jb. Points 4883

"L'optimisation prématurée est la racine de tout mal."

Avec cela fermement à l'esprit, nous allons le faire! Une fois vos applications atteint un certain point, la dénormalisation des données est très commun. Fait correctement, il peut sauver de nombreuses coûteuses recherches en base de données au prix d'un peu plus de ménage.

Pour revenir un list de ami noms que nous aurons besoin de créer un personnalisé Django classe de Champ qui sera de retour une liste lors de l'accès.

David Cramer a publié un guide pour la création d'un SeperatedValueField sur son blog. Voici le code:

from django.db import models

class SeparatedValuesField(models.TextField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.token = kwargs.pop('token', ',')
        super(SeparatedValuesField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, list):
            return value
        return value.split(self.token)

    def get_db_prep_value(self, value):
        if not value: return
        assert(isinstance(value, list) or isinstance(value, tuple))
        return self.token.join([unicode(s) for s in value])

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)

La logique de ce code traite de la sérialisation et la désérialisation des valeurs à partir de la base de données en Python et vice-versa. Maintenant, vous pouvez importer et d'utiliser notre champ personnalisé dans la classe du modèle:

from django.db import models
from custom.fields import SeparatedValuesField 

class Person(models.Model):
    name = models.CharField(max_length=64)
    friends = SeparatedValuesField()

101voto

Andrew Hare Points 159332

Cette relation ne serait-elle pas mieux exprimée en tant que relation de clé étrangère un-à-plusieurs dans une table Friends ? Je comprends que myFriends sont que des chaînes, mais je pense qu’une meilleure conception consisterait à créer un modèle Friend et que MyClass contiennent une relation de clé étrangère avec le table résultante.

68voto

mindthief Points 2074

Un moyen simple de stocker une liste de Django est de les convertir en une chaîne JSON, et enregistrer en tant que Texte dans le modèle. Vous pouvez ensuite récupérer la liste par la conversion de la (JSON) de la chaîne de retour dans une liste python. Voici comment:

La "liste" sont stockées dans votre Django modèle comme suit:

class MyModel(models.Model):
    myList = models.TextField(null=True) # JSON-serialized (text) version of your list

De votre point de vue/contrôleur de code:

Le stockage de la liste dans la base de données:

import simplejson as json # this would be just 'import json' in Python 2.7 and later
...
...

myModel = MyModel()
listIWantToStore = [1,2,3,4,5,'hello']
myModel.myList = json.dumps(listIWantToStore)
myModel.save()

La récupération de la liste de la base de données:

jsonDec = json.decoder.JSONDecoder()
myPythonList = jsonDec.decode(myModel.myList)

Sur le plan conceptuel, voici ce qu'il se passe:

>>> myList = [1,2,3,4,5,'hello']
>>> import simplejson as json
>>> myJsonList = json.dumps(myList)
>>> myJsonList
'[1, 2, 3, 4, 5, "hello"]'
>>> myJsonList.__class__
<type 'str'>
>>> jsonDec = json.decoder.JSONDecoder()
>>> myPythonList = jsonDec.decode(myJsonList)
>>> myPythonList
[1, 2, 3, 4, 5, u'hello']
>>> myPythonList.__class__
<type 'list'>

17voto

sebleblanc Points 586

Comme c'est une vieille question, et Django techniques doivent avoir beaucoup changé depuis, cette réponse reflète Django version 1.4, et est le plus susceptible applicable pour v 1.5.

Django utilise par défaut des bases de données relationnelles; vous devriez faire usage de 'em. Carte amitiés, les relations de la base de données (contraintes de clé étrangère) avec l'utilisation de ManyToManyField. Cela vous permet d'utiliser RelatedManagers pour friendlists, qui utilisent smart querysets. Vous pouvez utiliser toutes les méthodes disponibles tels que filter ou values_list.

À l'aide de ManyToManyField relations et propriétés:

class MyDjangoClass(models.Model):
    name = models.CharField(...)
    friends = models.ManyToManyField("self")

    @property
    def friendlist(self):
        # Watch for large querysets: it loads everything in memory
        return list(self.friends.all())

Vous pouvez accéder à un utilisateur de la liste d'amis de cette façon:

joseph = MyDjangoClass.objects.get(name="Joseph")
friends_of_joseph = joseph.friendlist

Toutefois, de noter que ces relations sont symétriques: si Joseph est un ami de Bob, Bob est un ami de Joseph.

10voto

drozzy Points 7887
class Course(models.Model):
   name = models.CharField(max_length=256)
   students = models.ManyToManyField(Student)

class Student(models.Model):
   first_name = models.CharField(max_length=256)
   student_number = models.CharField(max_length=128)
   # other fields, etc...

   friends = models.ManyToManyField('self')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X