Actuellement, j'ai beaucoup d'objets python dans mon code similaires à ceux-ci:
class MyClass():
def __init__(self, name, friends):
self.myName = name
self.myFriends = [str(x) for x in friends]
Maintenant, je veux transformer ceci 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?
Comme la liste est une structure de données commune en python, je m'attendais à ce qu'il y ait un champ de modèle Django). Je sais que je peux utiliser une relation ManyToMany ou OneToMany, mais j'espérais pour éviter cette indirection supplémentaire dans le code.
Modifier:
J'ai ajouté ceci 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 Friends
? Je comprends que myFriends
ne sont que des chaînes, mais je pense qu’une meilleure conception consisterait à créer un modèle Friend
et à avoir MyClass
à contenir une relation de clé étrangère avec la table résultante.
Avec cela fermement en tête, faisons ceci! Une fois que vos applications ont atteint un certain point, la dénormalisation des données est très courante. Fait correctement, il peut économiser de nombreuses recherches de base de données coûteuses au détriment d'un peu plus de ménage.
Pour renvoyer un list
de noms d'amis, nous devons créer une classe personnalisée Django) qui renverra une liste lors de l'accès.
David Cramer a publié un guide sur 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)
return self.get_db_prep_value(value)
La logique de ce code traite de la sérialisation et de la désérialisation des valeurs de la base de données à Python et vice-versa. Vous pouvez désormais importer et utiliser facilement 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 simplement à la convertir en chaîne JSON, puis à l'enregistrer en tant que texte dans le modèle. Vous pouvez ensuite récupérer la liste en convertissant le fichier (JSON). chaîne en arrière dans 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 du contrôleur:
Stocker 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()
Récupération de la liste de la base de données:
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__
<type 'str'>
>>> jsonDec = json.decoder.JSONDecoder()
>>> myPythonList = jsonDec.decode(myJsonList)
>>> myPythonList
[1, 2, 3, 4, 5, u'hello']
>>> myPythonList.__class__
<type 'list'>
Si vous utilisez Django> = 1.9 avec Postgres, vous pouvez utiliser ArrayField avantages
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 comme base_field. Vous pouvez également spécifier une taille. ArrayField peut être imbriqué pour stocker des tableaux multidimensionnels.
Il est également possible d'imbriquer des champs de tableau:
from Django.contrib.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 l'a mentionné, il est également possible d'interroger directement des éléments. Documentation référence
Comme il s’agit d’une question ancienne et que les techniques Django doivent avoir changé considérablement depuis, cette réponse correspond à Django version 1.4, et s’applique très probablement à la version 1.5.
Django utilise par défaut des bases de données relationnelles; vous devriez les utiliser. Mappez des amitiés sur des relations de base de données (contraintes de clé étrangère) à l'aide de ManyToManyField. Cela vous permet d'utiliser RelatedManagers pour les listes d'amis, qui utilisent des ensembles de requêtes intelligents. Vous pouvez utiliser toutes les méthodes disponibles telles que filter
ou values_list
.
Utilisation 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 à 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étriques: si Joseph est un ami de Bob, alors Bob est un ami de Joseph.
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')
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/contrib/postgres/fields/
Rappelez-vous que cela doit éventuellement se retrouver dans une base de données relationnelle. Donc, en utilisant des relations vraiment est la manière habituelle de résoudre ce problème. Si vous souhaitez absolument stocker une liste dans l'objet même, vous pouvez le séparer par des virgules, par exemple, et le stocker dans une chaîne, puis fournir des fonctions d'accès permettant de scinder la chaîne en une liste. Avec cela, vous serez limité à un nombre maximal de chaînes et vous perdrez des requêtes efficaces.
Vous pouvez stocker pratiquement n'importe quel objet en utilisant un Django Pickle Field, comme cet extrait de code:
Stocker une liste de chaînes dans Django model:
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 comme ça:
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."
L'utilisation d'une relation un-à-plusieurs (FK de Friend à la classe parente) rendra votre application plus évolutive (vous pourrez étendre trivialement l'objet Friend avec des attributs supplémentaires allant au-delà du simple nom). Et donc c'est la meilleure façon