** редактировать 30.11.2015 : в python 3 глобальная переменная модуля __metaclass__
равна , больше не поддерживается .
Кроме того, по состоянию на Django 1.10
класс SubfieldBase
был устарел :
django.db.models.fields.subclassing.SubfieldBase
устарел и будет удален в Django 1.10.
Исторически, он использовался для обработки полей, где необходимо преобразование типов при загрузке из базы данных,
но он не использовался в .values()
вызовах или в агрегатах. Он был заменен на from_db_value()
.
Обратите внимание, что новый подход не вызывает метод to_python()
при назначении, как это было в случае с SubfieldBase
.
Поэтому, как предлагается в from_db_value()
документации и в этом примере , это решение должно быть изменено на:
class CharNullField(models.CharField):
"""
Subclass of the CharField that allows empty strings to be stored as NULL.
"""
description = "CharField that stores NULL but returns ''."
def from_db_value(self, value, expression, connection, contex):
"""
Gets value right out of the db and changes it if its ``None``.
"""
if value is None:
return ''
else:
return value
def to_python(self, value):
"""
Gets value right out of the db or an instance, and changes it if its ``None``.
"""
if isinstance(value, models.CharField):
# If an instance, just return the instance.
return value
if value is None:
# If db has NULL, convert it to ''.
return ''
# Otherwise, just return the value.
return value
def get_prep_value(self, value):
"""
Catches value right before sending to db.
"""
if value == '':
# If Django tries to save an empty string, send the db None (NULL).
return None
else:
# Otherwise, just pass the value.
return value
Я думаю, что лучший способ, чем переопределение cleaned_data в админке, - это создать подкласс charfield - таким образом, независимо от того, какая форма обращается к полю, она будет «просто работать». Вы можете поймать ''
непосредственно перед отправкой в базу данных и поймать NULL сразу после того, как он выйдет из базы данных, а остальная часть Django не будет знать / заботиться. Быстрый и грязный пример:
from django.db import models
class CharNullField(models.CharField): # subclass the CharField
description = "CharField that stores NULL but returns ''"
__metaclass__ = models.SubfieldBase # this ensures to_python will be called
def to_python(self, value):
# this is the value right out of the db, or an instance
# if an instance, just return the instance
if isinstance(value, models.CharField):
return value
if value is None: # if the db has a NULL (None in Python)
return '' # convert it into an empty string
else:
return value # otherwise, just return the value
def get_prep_value(self, value): # catches value right before sending to db
if value == '':
# if Django tries to save an empty string, send the db None (NULL)
return None
else:
# otherwise, just pass the value
return value
Для моего проекта я поместил это в файл extras.py
, который находится в корне моего сайта, тогда я могу просто from mysite.extras import CharNullField
в файле models.py
моего приложения. Поле действует как CharField - просто не забудьте установить blank=True, null=True
при объявлении поля, иначе Django выдаст ошибку проверки (поле обязательно) или создаст столбец БД, который не принимает NULL.