python - google - run django app locally
Cómo crear un campo de lista en django (7)
Considere django-jsonfield , las ventajas son:
- Guarde y cargue objetos de listas nativas, no necesita conversión
- Solución bien probada y madura
- Podría tener otras ventajas dentro de su proyecto
- Admite filtrado en la base de datos y expresiones regulares (si es necesario)
además:
- Soporte cruzado
- Admite Python 2.7 a Python 3.4 y Django 1.4 a 1.8
- Realmente fácil :)
¿Cómo creo un ListField en Django (Python) como la propiedad ListProperty en Google App Engine (Python)? Mi información es una lista como esta: 3,4,5,6,7,8
.
¿Qué propiedad debo definir y cómo obtendré valores de ella?
Hago esto:
def get_comma_field(self, field):
data = getattr(self, field)
if data:
return data.split('','')
return []
def set_comma_field(self, val, field):
if isinstance(val, types.StringTypes):
setattr(self, field, val)
else:
setattr(self, field, '',''.join(val))
def make_comma_field(field):
def getter(self):
return get_comma_field(self, field)
def setter(self, val):
return set_comma_field(self, val, field)
return property(getter, setter)
class MyModel(models.Model):
_myfield = models.CharField(max_length=31)
myfield = make_comma_field(''_myfield'')
Pero supongo que ahora podría ser excesivo. Necesitaba bastantes, por lo que escribí la función make_comma_field.
Intente utilizar un CommaSeparatedIntegerField
que se documenta aquí: http://docs.djangoproject.com/en/1.2/ref/models/fields/#commaseparatedintegerfield
Revisando esto con un tipo ListField
que puede usar. Pero hace algunas suposiciones, como el hecho de que no está almacenando tipos complejos en su lista. Por este motivo, utilicé ast.literal_eval()
para exigir que solo los tipos simples incorporados se puedan almacenar como miembros en un ListField
:
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 Dummy(models.Model):
mylist = ListField()
Tomándolo por una vuelta:
>>> from foo.models import Dummy, ListField
>>> d = Dummy()
>>> d.mylist
[]
>>> d.mylist = [3,4,5,6,7,8]
>>> d.mylist
[3, 4, 5, 6, 7, 8]
>>> f = ListField()
>>> f.get_prep_value(d.numbers)
u''[3, 4, 5, 6, 7, 8]''
Ahí lo tiene que una lista se almacena en la base de datos como una cadena unicode, y cuando se tira hacia atrás se ejecuta a través de ast.literal_eval()
.
Anteriormente, sugerí esta solución en esta publicación de blog sobre Custom Fields en Django :
Una alternativa al CommaSeparatedIntegerField, le permite almacenar cualquier valor separado. También puede especificar opcionalmente un parámetro de token.
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)
Si bien la respuesta de Jonathan es genial, recibí el siguiente error al intentar usar el comando dumpdata
:
Error: Unable to serialize database: get_db_prep_value() takes at least 3 arguments (2 given)
El problema es que la llamada self.get_db_prep_value
en el método value_to_string
requiere que se proporcione un valor de connection
(al menos en Django 1.4.10 , que es lo que estoy usando). Al final, realmente no vi lo que se ganaba llamando al método value_to_string
en primer lugar y lo __init__
, junto con el método __init__
innecesario. Esto es con lo que terminé:
class ListField(models.TextField):
__metaclass__ = models.SubfieldBase
description = "Stores a python list"
def to_python(self, value):
if not value:
value = []
if isinstance(value, list):
return value
converted = ast.literal_eval(value)
if not isinstance(converted, list):
raise ValueError(''Value "%s" not a list'' % converted)
return converted
Si está utilizando postgresql, django admite postgres con arrayfield .
Simplemente, puede almacenar la lista como una cadena y cada vez que la use, use ast.literal_eval () para convertir primero a lista de cadena. p.ej:
import ast
class MyModel(models.Model):
field_1 = models.any kind of field()
list_field = models.CharField(max_length=255)
def get_list(self):
list = ast.literal_eval(self.list_field)
return list
De la misma manera en las vistas, etc. Al guardar, haga opraciones en la lista y finalmente conviértalo en una cadena de la siguiente manera:
model.list_field = str(list)
model.save()