В настоящее время в моем коде много объектов Python, похожих на следующие:
class MyClass():
def __init__(self, name, friends):
self.myName = name
self.myFriends = [str(x) for x in friends]
Теперь я хочу превратить это в модель Django, где self.myName - это строковое поле, а self.myFriends - это список строк.
from django.db import models
class myDjangoModelClass():
myName = models.CharField(max_length=64)
myFriends = ??? # what goes here?
Поскольку список - это такая распространенная структура данных в Python, я ожидал, что для него будет поле модели Django. Я знаю, что могу использовать отношения ManyToMany или OneToMany, но я надеялся избежать этого дополнительного косвенного обращения в коде.
Редактировать:
Я добавил этот связанный вопрос , который может оказаться полезным.
python
django
django-models
горевать
источник
источник
Ответы:
Разве это отношение не было бы лучше выражено как отношение внешнего ключа «один ко многим» к
Friends
таблице? Я понимаю, чтоmyFriends
это просто строки, но я думаю, что лучше было бы создатьFriend
модель, котораяMyClass
содержала бы привязку внешнего ключа к результирующей таблице.источник
«Преждевременная оптимизация - корень всех зол».
Имея это в виду, давайте сделаем это! Как только ваши приложения достигают определенной точки, денормализация данных становится очень распространенным явлением. При правильном выполнении он может сэкономить множество дорогостоящих поисков в базе данных за счет немного большего количества операций.
Чтобы вернуть список
list
имен друзей, нам нужно создать собственный класс Django Field, который будет возвращать список при доступе.Дэвид Крамер опубликовал руководство по созданию SeperatedValueField в своем блоге. Вот код:
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)
Логика этого кода связана с сериализацией и десериализацией значений из базы данных в Python и наоборот. Теперь вы можете легко импортировать и использовать наше настраиваемое поле в классе модели:
from django.db import models from custom.fields import SeparatedValuesField class Person(models.Model): name = models.CharField(max_length=64) friends = SeparatedValuesField()
источник
my_vals = SeparatedValuesField(blank=True, default="")
но с получением IntegrityError из-за NULL. Аргумент по умолчанию не передается правильно?to_python
больше не вызывается чтение. Таким образом, чтобы эта работа работала, вам нужно добавить:def from_db_value(self, value, expression, connection, context): return self.to_python(value)
Простой способ сохранить список в Django - просто преобразовать его в строку JSON, а затем сохранить его как текст в модели. Затем вы можете получить список, преобразовав строку (JSON) обратно в список Python. Вот как:
«Список» будет храниться в вашей модели Django следующим образом:
class MyModel(models.Model): myList = models.TextField(null=True) # JSON-serialized (text) version of your list
В вашем коде представления / контроллера:
Сохранение списка в базе данных:
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()
Получение списка из базы данных:
По идее, вот что происходит:
>>> 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'>
источник
Если вы используете Django> = 1.9 с Postgres, вы можете использовать преимущества ArrayField
Также можно вкладывать поля массива:
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, )
Как упоминал @ thane-brimhall, также можно напрямую запрашивать элементы. Справочная документация
источник
Поскольку это старый вопрос, и методы Django должны были значительно измениться с тех пор, этот ответ отражает версию Django 1.4 и, скорее всего, применим к версии 1.5.
Django по умолчанию использует реляционные базы данных; вы должны использовать их. Сопоставьте дружеские отношения с отношениями базы данных (ограничения внешнего ключа) с помощью ManyToManyField. Это позволяет использовать связанные менеджеры для списков друзей, в которых используются интеллектуальные наборы запросов. Вы можете использовать все доступные методы, такие как
filter
илиvalues_list
.Использование
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())
Вы можете получить доступ к списку друзей пользователя следующим образом:
joseph = MyDjangoClass.objects.get(name="Joseph") friends_of_joseph = joseph.friendlist
Однако обратите внимание, что эти отношения симметричны: если Джозеф - друг Боба, то Боб - друг Джозефа.
источник
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')
источник
Помните, что в конечном итоге это должно оказаться в реляционной базе данных. Так что использование отношений действительно является обычным способом решения этой проблемы. Если вы абсолютно настаиваете на хранении списка в самом объекте, вы можете сделать его, например, разделенным запятыми и сохранить его в строке, а затем предоставить функции доступа, которые разбивают строку на список. При этом вы будете ограничены максимальным количеством строк, и вы потеряете эффективные запросы.
источник
Если вы используете postgres, вы можете использовать что-то вроде этого:
class ChessBoard(models.Model): board = ArrayField( ArrayField( models.CharField(max_length=10, blank=True), size=8, ), size=8, )
если вам нужно больше информации, вы можете прочитать по ссылке ниже: https://docs.djangoproject.com/pt-br/1.9/ref/contrib/postgres/fields/
источник
Вы можете сохранить практически любой объект, используя поле рассола Django, как этот фрагмент:
http://www.djangosnippets.org/snippets/513/
источник
Сохранение списка строк в модели 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
и вы можете назвать это так:
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."
источник
Использование отношения «один ко многим» (FK от Friend к родительскому классу) сделает ваше приложение более масштабируемым (поскольку вы можете тривиально расширить объект Friend с помощью дополнительных атрибутов, помимо простого имени). Таким образом, это лучший способ
источник
Мое решение, может быть, это кому-то поможет:
import json from django.db import models class ExampleModel(models.Model): _list = models.TextField(default='[]') @property def list(self): return json.loads(self._list) @list.setter def list(self, value): self._list = json.dumps(self.list + value)
источник