Django: List box in model?

In my model I want a triplet list box. for example, [[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]] . Is there a field that can store this data in the database?

+57
django django-orm
Mar 12 '14 at 1:34
source share
9 answers

You can convert it to a string using JSON and save it as a 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 to your class to automatically convert it 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 are using Django 1.9 and postgresql, there is a new class called JSONField, you should use it instead. Here is a link to it

Youtube talks a lot about JSON and PostgreSQL arrays. Look, this is very good information.

+81
Mar 12 '14 at 6:47
source share

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

Thus, the data structure will be known to the underlying database. In addition, ORM provides special functionality for this.

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

(Change: Updated links to the latest Django LTS, this feature has been in place since at least 1.8.)

+21
Jun 13 '15 at 16:01
source share

If you are using a more modern version of Django, such as 1.10, and your database is Postgres, there is a new ArrayField that is better to use than django-taggit or other alternatives, as it is native to the Django framework.

 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, ) 
+20
Dec 08 '16 at 19:35
source share

I think this will help you.

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

Example:

 >>> 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]]
 >>> 
+16
Mar 12 '14 at 6:35
source share

Just use the JSON field that third-party packages provide:

In this case, you do not need to worry about serializing the field value - this will happen under the hood.

Hope this helps.

+8
Mar 12 '14 at 17:49
source share

You can flatten the list and then save the values โ€‹โ€‹of the CommaSeparatedIntegerField . When you read back from the database, just group the values โ€‹โ€‹back into three.

Disclaimer: according to the database normalization theory, it is better not to store collections in separate fields; instead, you will be prompted to store the values โ€‹โ€‹in these triplets in your own fields and bind them using foreign keys. However, in the real world it is too cumbersome / slow.

+1
Mar 12 '14 at 6:26
source share

This is a pretty old topic, but since it returns when searching for the โ€œdjango list boxโ€, I will share the user code for the django list box, which I modified to work with Python 3 and Django 2. Now it supports the admin interface and does not use eval (which is huge breach of security in Prashant Gaur 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) 
+1
Nov 20 '18 at 0:48
source share

If you use the Google App Engine or MongoDB as the backend, and you use the djangoappengine library, there is a built-in ListField that does exactly what you want. In addition, it is easy to query Listfield to search for all objects that contain an item in the list.

0
Mar 25 '16 at 13:23
source share

With my current reputation, I have no way to comment, so I choose the answer that refers to the comments for the sample code in the response of Prashant Gaura (thanks, Gaura - it was useful!) - his example is for python2, since python3 has no method

  unicode 
,

The replacement below for the function

  get_prep_value (self, value): 
should work with Django working with python3 (I will use this code soon - until I tested it). Please note that I am passing parameters
  encoding = 'utf-8', errors = 'ignore' 
at
  decode () 
and
  unicode () methods 
. The encoding should match your Django settings.py configuration, and the transfer
  errors = 'ignore' 
is optional (and can lead to loss of data without displaying messages instead of an exception that, in rare cases, incorrectly configures 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)
 ...




0
Jul 26 '18 at 18:31
source share



All Articles