Django: List field in model?

后端 未结 9 1569
感动是毒
感动是毒 2020-11-29 18:38

In my model, I want a field that has a list of triplets. e.g. [[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]. Is there a field that can store this data in the da

相关标签:
9条回答
  • 2020-11-29 19:17

    If you're on Django 1.10 or newer AND Postgres as your database, you can use ArrayField. It's better to use than django-taggit or other alternatives, as it's native to the Django framework. https://docs.djangoproject.com/en/3.1/ref/contrib/postgres/fields/#arrayfield

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

    If you're on Django 3.1 or newer they've added support for JSONField with most database backends (MariaDB 10.2.7+, MySQL 5.7.8+, Oracle, PostgreSQL, and SQLite 3.9.0+). You can use this to store your Array!

    https://docs.djangoproject.com/en/3.1/ref/models/fields/#jsonfield

    from django.db import models
    
    class ChessBoard(models.Model):
        list_of_pieces = models.JSONField()
    
    0 讨论(0)
  • 2020-11-29 19:18

    If you are using Google App Engine or MongoDB as your backend, and you are using the djangoappengine library, there is a built in ListField that does exactly what you want. Further, it's easy to query the Listfield to find all objects that contain an element in the list.

    0 讨论(0)
  • 2020-11-29 19:19

    With my current reputation I have no ability to comment, so I choose answer referencing comments for sample code in reply by Prashant Gaur (thanks, Gaur - this was helpful!) - his sample is for python2, since python3 has no

    unicode
    method.

    The replacement below for function

    get_prep_value(self, value):
    should work with Django running with python3 (I'll use this code soon - yet not tested). Note, though, that I'm passing
    encoding='utf-8', errors='ignore'
    parameters to
    decode()
    and
    unicode() methods
    . Encoding should match your Django settings.py configuration and passing
    errors='ignore'
    is optional (and may result in silent data loss instead of exception whith misconfigured django in rare cases).

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

    0 讨论(0)
  • 2020-11-29 19:31

    It's quite an old topic, but since it is returned when searching for "django list field" I'll share the custom django list field code I modified to work with Python 3 and Django 2. It supports the admin interface now and not uses eval (which is a huge security breach in Prashant Gaur's code).

    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)
    
    0 讨论(0)
  • 2020-11-29 19:33

    If you are using PostgreSQL, you can use ArrayField with a nested ArrayField: https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/

    This way, the data structure will be known to the underlying database. Also, the ORM brings special functionality for it.

    Note that you will have to create a GIN index by yourself, though (see the above link, further down: https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#indexing-arrayfield).

    (Edit: updated links to newest Django LTS, this feature exists at least since 1.8.)

    0 讨论(0)
  • 2020-11-29 19:38

    You can convert it into string by using JSON and store it as string.

    For example,

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

    You can add a method into your class to convert it automatically for you.

    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)
    

    If you're using Django 1.9 and postgresql, there is a new class called JSONField, you should use it instead. Here is a link to it

    There is a good talk about PostgreSQL JSONs and Arrays on youtube. Watch it, it has very good information.

    0 讨论(0)
提交回复
热议问题