Подтвердить что ты не робот

Django: Поле списка в модели?

В моей модели я хочу поле со списком триплетов. например, [[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]. Есть ли поле, которое может хранить эти данные в базе данных?

4b9b3361

Ответ 1

Вы можете преобразовать его в строку, используя JSON, и сохранить его как строку.

Например,

In [3]: json.dumps([[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]])

Out[3]: '[[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]'

Вы можете добавить метод в свой класс, чтобы автоматически преобразовать его для вас.

import json


class Foobar(models.Model):
    foo = models.CharField(max_length=200)

    def set_foo(self, x):
        self.foo = json.dumps(x)

    def get_foo(self):
        return json.loads(self.foo)

Если вы используете Django 1.9 и postgresql, есть новый класс с именем JSONField, вы должны использовать его вместо этого. Вот ссылка на него

На youtube много говорят о JSON и массивах PostgreSQL. Посмотрите, это очень хорошая информация.

Ответ 2

Если вы используете PostgreSQL, вы можете использовать ArrayField с вложенным ArrayField: https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/

Таким образом, структура данных будет известна базовой базе данных. Кроме того, ORM предоставляет специальные функциональные возможности для этого.

Обратите внимание, что вам придется создать индекс GIN самостоятельно (см. Приведенную выше ссылку ниже): https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#indexing-arrayfield).,

(Изменение: обновлены ссылки на новейшие Django LTS, эта функция существует по крайней мере начиная с 1.8.)

Ответ 3

Если вы используете более современную версию Django, такую как 1.10, и ваша БД - Postgres, есть новый ArrayField, который лучше использовать, чем django-taggit или другие альтернативы, поскольку он является родным для фреймворка Django.

from django.db import models
from django.contrib.postgres.fields import ArrayField

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

Ответ 4

Я думаю, это поможет вам.

from django.db import models
import ast

class ListField(models.TextField):
    __metaclass__ = models.SubfieldBase
    description = "Stores a python list"

    def __init__(self, *args, **kwargs):
        super(ListField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value:
            value = []

        if isinstance(value, list):
            return value

        return ast.literal_eval(value)

    def get_prep_value(self, value):
        if value is None:
            return value

        return unicode(value)

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

class ListModel(models.Model):
    test_list = ListField()

Пример:

>>> ListModel.objects.create(test_list= [[1,2,3], [2,3,4,4]])

>>> ListModel.objects.get(id=1)

>>> o = ListModel.objects.get(id=1)
>>> o.id
1L
>>> o.test_list
[[1, 2, 3], [2, 3, 4, 4]]
>>> 

Ответ 5

Просто используйте поле JSON, которое предоставляют сторонние пакеты:

В этом случае вам не нужно заботиться о сериализации значения поля - это произойдет под капотом.

Надеюсь, что это поможет.

Ответ 6

Вы можете сгладить список, а затем сохранить значения CommaSeparatedIntegerField. Когда вы читаете назад из базы данных, просто сгруппируйте значения обратно в три.

Отказ от ответственности: согласно теории нормализации базы данных, лучше не хранить коллекции в отдельных полях; вместо этого вам будет предложено сохранить значения в этих триплетах в своих собственных полях и связать их с помощью внешних ключей. Однако в реальном мире это слишком громоздко/медленно.

Ответ 7

Это довольно старая тема, но так как она возвращается при поиске "поля списка django", я поделюсь пользовательским кодом поля списка django, который я модифицировал для работы с Python 3 и Django 2. Теперь он поддерживает интерфейс администратора и не использует eval (что является огромным нарушением безопасности в коде Prashant Gaur).

from django.db import models
from typing import Iterable

class ListField(models.TextField):
    """
    A custom Django field to represent lists as comma separated strings
    """

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

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs['token'] = self.token
        return name, path, args, kwargs

    def to_python(self, value):

        class SubList(list):
            def __init__(self, token, *args):
                self.token = token
                super().__init__(*args)

            def __str__(self):
                return self.token.join(self)

        if isinstance(value, list):
            return value
        if value is None:
            return SubList(self.token)
        return SubList(self.token, value.split(self.token))

    def from_db_value(self, value, expression, connection):
        return self.to_python(value)

    def get_prep_value(self, value):
        if not value:
            return
        assert(isinstance(value, Iterable))
        return self.token.join(value)

    def value_to_string(self, obj):
        value = self.value_from_object(obj)
        return self.get_prep_value(value)

Ответ 8

Если вы используете Google App Engine или MongoDB в качестве бэкэнд, и вы используете библиотеку djangoappengine, есть встроенный ListField, который делает именно то, что вы хотите. Кроме того, легко запросить Listfield для поиска всех объектов, которые содержат элемент в списке.

Ответ 9

С моей текущей репутацией у меня нет возможности комментировать, поэтому я выбираю ответ, ссылающийся на комментарии для примера кода в ответе Прашанта Гаура (спасибо, Гаур - это было полезно!) - его пример для python2, поскольку у python3 нет метода

unicode
,

Приведенная ниже замена для функции

get_prep_value(self, value):
должна работать с Django, работающим с python3 (я скоро буду использовать этот код - пока не тестировал). Обратите внимание, что я передаю параметры
encoding='utf-8', errors='ignore'
в
decode()
и
unicode() methods
. Кодировка должна соответствовать вашей конфигурации Django settings.py, и передача
errors='ignore'
является необязательной (и может привести к потере данных без вывода сообщений вместо исключения, которое в редких случаях неверно конфигурирует django).
import sys

...

    def get_prep_value(self, value):
        if value is None:
            return value
        if sys.version_info[0] >= 3:
            if isinstance(out_data, type(b'')):
                return value.decode(encoding='utf-8', errors='ignore')
        else:
            if isinstance(out_data, type(b'')):
                return unicode(value, encoding='utf-8', errors='ignore')
        return str(value)
...