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

Actuellement, j’ai beaucoup d’objects python dans mon code, comme suit:

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

Maintenant, je veux transformer cela en un modèle Django, où self.myName est un champ de chaîne et self.myFriends est une liste de chaînes.

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

Étant donné que la liste est une structure de données si commune en python, je m’attendais à ce qu’il y ait un champ modèle Django. Je sais que je peux utiliser une relation ManyToMany ou OneToMany, mais j’espérais éviter cette indirection supplémentaire dans le code.

Modifier:

J’ai ajouté cette question connexe , que les gens peuvent trouver utile.

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

“L’optimisation prématurée est la racine de tout Mal.”

Avec cela en tête, faisons-le! Une fois que vos applications ont atteint un certain point, la dénormalisation des données est très courante. Fait correctement, il peut sauver de nombreuses recherches de bases de données coûteuses au prix d’un peu plus de ménage.

Pour renvoyer une list de noms d’amis, nous devrons créer une classe de champs Django personnalisée qui renverra une liste lorsque vous y accéderez.

David Cramer a publié un guide pour créer 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_ssortingng(self, obj): value = self._get_val_from_obj(obj) return self.get_db_prep_value(value) 

La logique de ce code concerne la sérialisation et la désérialisation des valeurs de la firebase database vers Python et inversement. Maintenant, vous pouvez facilement importer et utiliser notre champ personnalisé dans la classe de modèle:

 from django.db import models from custom.fields import SeparatedValuesField class Person(models.Model): name = models.CharField(max_length=64) friends = SeparatedValuesField() 

Un moyen simple de stocker une liste dans Django consiste à le convertir en une chaîne JSON, puis à l’enregistrer en tant que texte dans le modèle. Vous pouvez ensuite récupérer la liste en convertissant la chaîne (JSON) en une liste Python. Voici comment:

La “liste” serait stockée dans votre modèle Django comme ceci:

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

Dans votre vue / code de contrôleur:

Stocker la liste dans la firebase database:

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

Récupération de la liste de la firebase database:

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

Conceptuellement, voici ce qui 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__  >>> jsonDec = json.decoder.JSONDecoder() >>> myPythonList = jsonDec.decode(myJsonList) >>> myPythonList [1, 2, 3, 4, 5, u'hello'] >>> myPythonList.__class__  

Comme il s’agit d’une ancienne question, et que les techniques de Django doivent avoir changé de manière significative depuis, cette réponse reflète la version 1.4 de Django, et est très probablement applicable à la version 1.5.

Django utilise par défaut des bases de données relationnelles; vous devriez les utiliser. Mapper les amitiés aux relations de firebase database (contraintes de clé étrangère) avec l’utilisation de ManyToManyField. Cela vous permet d’utiliser RelatedManagers pour les listes d’amis, qui utilisent des jeux de requêtes intelligents. Vous pouvez utiliser toutes les méthodes disponibles telles que filter ou values_list .

Utilisation des relations et des propriétés de ManyToManyField :

 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 à la liste d’amis d’un utilisateur de cette manière:

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

Notez cependant que ces relations sont symésortingques: si Joseph est un ami de Bob, alors Bob est un ami de Joseph.

Si vous utilisez Django> = 1.9 avec Postgres, vous pouvez utiliser les avantages ArrayField

Un champ pour stocker des listes de données. La plupart des types de champs peuvent être utilisés, vous passez simplement une autre instance de champ en tant que base_field. Vous pouvez également spécifier une taille. ArrayField peut être nested pour stocker des tableaux multidimensionnels.

Il est également possible d’imbriquer des champs de tableau:

 from django.consortingb.postgres.fields import ArrayField from django.db import models class ChessBoard(models.Model): board = ArrayField( ArrayField( models.CharField(max_length=10, blank=True), size=8, ), size=8, ) 

Comme @ thane-brimhall a mentionné, il est également possible d’interroger directement des éléments. Référence de la documentation

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

Rappelez-vous que cela doit finir par se retrouver dans une firebase database relationnelle. Donc, utiliser les relations est la manière commune de résoudre ce problème. Si vous insistez absolument pour stocker une liste dans l’object lui-même, vous pouvez par exemple le séparer par une virgule et le stocker dans une chaîne, puis fournir des fonctions d’accesseur qui divisent la chaîne en une liste. Avec cela, vous serez limité à un nombre maximum de chaînes, et vous perdrez des requêtes efficaces.

Si vous utilisez postgres, vous pouvez utiliser quelque chose comme ceci:

 class ChessBoard(models.Model): board = ArrayField( ArrayField( models.CharField(max_length=10, blank=True), size=8, ), size=8, ) 

Si vous avez besoin de plus de détails, vous pouvez lire le lien ci-dessous: https://docs.djangoproject.com/pt-br/1.9/ref/consortingb/postgres/fields/

Vous pouvez stocker virtuellement n’importe quel object en utilisant un Pickle Field de Django, comme cet extrait de code:

http://www.djangosnippets.org/snippets/513/

L’utilisation de la relation un-à-plusieurs (FK de Friend à la classe parente) rendra votre application plus évolutive (car vous pouvez élargir sortingvialement l’object Friend avec des atsortingbuts supplémentaires au-delà du nom simple). Et donc c’est le meilleur moyen

Stocker une liste de chaînes dans le modèle Django:

 class Bar(models.Model): foo = models.TextField(blank=True) def set_list(self, element): if self.foo: self.foo = self.foo + "," + element else: self.foo = element def get_list(self): if self.foo: return self.foo.split(",") else: None 

et vous pouvez l’appeler ainsi:

 bars = Bar() bars.set_list("str1") bars.set_list("str2") list = bars.get_list() if list is not None: for bar in list: print bar else: print "List is empty."