Si vous ajoutez une contrainte unique à un CharField non essentiel, une DuplicateError se produira. J'étais un peu accro à la création d'un champ qui enregistre Null au lieu de caractères vides lorsqu'il n'y a pas d'entrée, alors j'ai écrit un mémo.
Dans django, lorsque CharField et TextField sont enregistrés comme vides, ils sont enregistrés en tant que caractères vides au lieu de Null. Si IntegerField etc. est vide, Null est sauvegardé correctement, donc si vous vérifiez la source de django ce que vous faites J'ai trouvé la méthode suivante dans la classe IntegerField.
def get_prep_value(self, value):
value = super(IntegerField, self).get_prep_value(value)
if value is None:
return None
return int(value)
C'est comme une méthode qui convertit la valeur avant d'enregistrer la base de données, donc si vous renvoyez None lorsque le caractère est vide, Null sera enregistré.
class NullCharField(models.CharField):
def get_preg_value(self, value):
value = Super(NullCharField, self).get_preg_value(value)
return value if value else None
Pour le moment, cela économisera Null s'il n'y a pas d'entrée dans Form, etc.
Si vous ouvrez l'écran d'administration dans cet état, TypeError se produira.
Exception Value: coercing to Unicode: need string or buffer, NoneType found
Puisqu'il est dit que "pass string ou buffer", s'il est None, il semble qu'un traitement pour le convertir en caractères vides soit nécessaire.
J'ai pensé que je devrais réécrire la méthode to_string, mais cela ne fonctionne pas. Il semble qu'il soit nécessaire de passer django.db.models.SubfieldBase à la classe méta après diverses investigations. La valeur obtenue à partir de la base de données est entrée par setattr (voir la méthode d'initialisation de la classe Model de django.db.models.base). Si vous passez SubfieldBase à la classe meta, la méthode to_python sera appelée en interne à setattr.
C'est pourquoi j'ai spécifié meta et ajouté le traitement au moment de l'acquisition.
from django.db import models
from django.utils import six
class NullCharField(six.with_metaclass(models.SubfieldBase, models.CharField)):
def get_preg_value(self, value):
value = super(NullCharField, self).get_preg_value(value)
return value if value else None
def to_python(self, value):
value = super(NullCharField, self).to_python(value)
return value if value is not None else u''
Je pensais que c'était peut-être quelque chose, et quand je l'ai recherché, c'était normal à Oscar. https://github.com/django-oscar/django-oscar/blob/master/src/oscar/models/fields/init.py
class NullCharField(six.with_metaclass(SubfieldBase, CharField)):
"""
CharField that stores '' as None and returns None as ''
Useful when using unique=True and forms. Implies null==blank==True.
When a ModelForm with a CharField with null=True gets saved, the field will
be set to '': https://code.djangoproject.com/ticket/9590
This breaks usage with unique=True, as '' is considered equal to another
field set to ''.
"""
description = "CharField that stores '' as None and returns None as ''"
def __init__(self, *args, **kwargs):
if not kwargs.get('null', True) or not kwargs.get('blank', True):
raise ImproperlyConfigured(
"NullCharField implies null==blank==True")
kwargs['null'] = kwargs['blank'] = True
super(NullCharField, self).__init__(*args, **kwargs)
def to_python(self, value):
val = super(NullCharField, self).to_python(value)
return val if val is not None else u''
def get_prep_value(self, value):
prepped = super(NullCharField, self).get_prep_value(value)
return prepped if prepped != u"" else None
def deconstruct(self):
"""
deconstruct() is needed by Django's migration framework
"""
name, path, args, kwargs = super(NullCharField, self).deconstruct()
del kwargs['null']
del kwargs['blank']
return name, path, args, kwargs
C'était presque là. J'ai vérifié les indicateurs nuls et vides avec init. En outre, il semble que l'écrasement de déconstruction soit nécessaire pour la migration.
Recommended Posts