[PYTHON] Erstellen Sie ein benutzerdefiniertes Feld, in dem Enum in Auswahlmöglichkeiten angegeben werden kann

Da enum34, das in Python 3.4 eingeführt und in Python 2.4 zurückportiert werden soll, praktisch ist, habe ich versucht, es in der Auswahloption von CharField anzugeben, konnte es jedoch nicht so verwenden, wie es ist, also habe ich es erstellt.

Referenz-URL

Betriebsumgebung

choicefield.py


# -*- encoding: utf-8 -*-
from django.db import models
from django.utils.functional import curry
import enum


class ChoiceField(models.CharField):
    u"""Aufzählung in Entscheidungen.Ein benutzerdefiniertes Feld, in dem Sie eine Unterklasse von Enum angeben können.
    """
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.enum = kwargs.get("choices", None)
        if self.enum and issubclass(self.enum, enum.Enum):
            kwargs["choices"] = self._from_enum()
            kwargs["max_length"] = self._calc_max_length()
        super(ChoiceField, self).__init__(*args, **kwargs)

    def _calc_max_length(self):
        u"""Suchen Sie die Zeichenfolgenlänge, die zum Speichern in der Datenbank erforderlich ist.
        """
        return max([len(unicode(item)) for item in self.enum])

    def _from_enum(self):
        u"""In einen Taple konvertieren, der in Auswahlmöglichkeiten angegeben werden kann.
        """
        return [(item, item.value) for item in self.enum]

    @staticmethod
    def _get_display(self, field):
        u"""Eine Methode, die für die Anzeige des Modells nachgerüstet wird
        """
        return getattr(self, field.attname).value

    def contribute_to_class(self, cls, name, virtual_only=False):
        super(ChoiceField, self).contribute_to_class(cls, name, virtual_only)
        setattr(cls, 'get_%s_display' % self.name, curry(self._get_display, field=self))
        #Nachrüstung an Enum-Klasse gemäß MaxLengthValidator
        setattr(self.enum, '__len__', lambda x: len(unicode(x)))

    def get_prep_value(self, value):
        if isinstance(value, basestring):
            return value
        return None if value is None else unicode(value)

    def to_python(self, value):
        if not value or not isinstance(value, basestring):
            return value

        try:
            return self.enum[value]
        except KeyError:
            for m in self.enum:
                if value == m:
                    return value
                if value == m.value:
                    return m
                if value == m.name:
                    return m
                if value.endswith(m.name):
                    return m
            raise Exception('%s is not a valid value for enum %s' % (value, self.enum))

Der Test sieht so aus

tests/tests_choicefield.py


# -*- encoding: utf-8 -*-
from django import test
from django.db import models
import enum
import os


class Gender(enum.Enum):
    __order__ = "Male Female"
    Male = u"männlich"
    Female = u"Weiblich"


class Person(models.Model):
    name = models.CharField(u"Name", max_length=255)
    gender = choices.ChoiceField(u"Sex", choices=Gender, max_length=255)

    class Meta:
        app_label = os.path.basename(os.path.abspath(os.path.join(os.path.split(__file__)[0], os.pardir)))


class PersonTest(test.TestCase):
    def test_choices(self):
        obj = Person.objects.create(name="John", gender=Gender.Male)
        self.assertEqual(Gender.Male, obj.gender)
        self.assertEqual(u"männlich", obj.get_gender_display())

    def test_get(self):
        obj1 = Person.objects.create(name="John", gender=Gender.Male)
        obj2 = Person.objects.get(name="John", gender=Gender.Male)
        self.assertEqual(obj1, obj2)

    def test_filter_in(self):
        obj1 = Person.objects.create(name="John", gender=Gender.Male)
        obj2 = Person.objects.create(name="Jane", gender=Gender.Female)
        actual = Person.objects.filter(gender__in=[Gender.Male, Gender.Female])
        self.assertItemsEqual([obj1, obj2], actual)

Recommended Posts

Erstellen Sie ein benutzerdefiniertes Feld, in dem Enum in Auswahlmöglichkeiten angegeben werden kann
[Kann in 10 Minuten erledigt werden] Erstellen Sie schnell eine lokale Website mit Django
Ich möchte eine Prioritätswarteschlange erstellen, die mit Python (2.7) aktualisiert werden kann.
Goroutine (parallele Steuerung), die im Feld eingesetzt werden kann
Goroutine, die im Feld verwendet werden kann (errgroup.Group Edition)
Bewertungsindex, der für GridSearchCV von sklearn angegeben werden kann
Erstellen Sie eine Funktion in Python
Erstellen Sie ein Wörterbuch in Python
Erstellen Sie eine Spinbox, die mit Tkinter in Binär angezeigt werden kann
Erstellen Sie eine Spinbox, die mit Tkinter in HEX angezeigt werden kann
Kann ich Datenwissenschaftler werden?
Erstellen Sie mit Flask einen CSV-Reader
Erstellen Sie einen DI-Container mit Python
Erstellen Sie eine Binärdatei in Python
Erstellen Sie eine zufällige Zeichenfolge in Python
Erstellen Sie mit Django einen LINE-Bot
[Python] Ein Programm, das ein Paar findet, das durch einen bestimmten Wert geteilt werden kann
Erstellen Sie eine Web-App, die mit Plotly Dash einfach visualisiert werden kann
Eine Geschichte, die Heroku, die in 5 Minuten gemacht werden kann, tatsächlich 3 Tage dauerte
Ich wollte ein Programm mit umgekehrter polnischer Notation in Python erstellen (Bestimmung, ob eine Zeichenfolge in einen numerischen Wert konvertiert werden kann)