[PYTHON] Django NullCharField

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.

Traitement au moment de l'enregistrement

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.

Traitement au moment de l'acquisition

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

vérifier la réponse

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

Django NullCharField
Django
mise à jour de Django
Django Note 4
Mémorandum Django
recherche django
Installation de Django
Résumé de Django
Test Django
Django # 2 (modèle)
Django Note 5
Django Hands On
Touchez django
Résumé de Django
Django Shoho
Django + Docker
Glossaire Django
Installation de Django
Django: Références
Django Note 1
Django Note 3
Django Note 2
Mémo Django
Construction de l'environnement Django
Django ~ édition settings.py ~
Django Heroku Deploy 1
Modèle HTML Django partie 2
Formulaire de demande Django 2
Django a commencé la partie 1
Modèle Django: ManyToManyField
Qu'est-ce que Django? .. ..
Modèle dans Django
Vue basée sur les fonctions Django
Tutoriel Python Django (5)
Mémo d'apprentissage Django
Tutoriel Python Django (2)
Notes de [Django] as_view ()
Premier défi Django
django makemigarations créeuperutilisateur
Sites liés à Django
Vérification de la version de Django
Django a commencé la partie 4
Prise en charge de l'internationalisation avec Django 1.9
CentOS8 --Jouer --Django
CentOS8 --Installer --Django
mémo du didacticiel django
[Django] Refaire la migration
construction d'environnement django
Tutoriel Python Django (8)
Tutoriel Python Django (6)
Configuration initiale de django
Démarrer le didacticiel Django 1
Modèle HTML Django
Astuces pour les modèles Django
Flux de travail Django Girls-3
Référence du projet Django
Django Heroku Deploy 2
CRUD avec Django
Résumé du filtre Django
Commande Django + Docker