Umgebung: Python 2.7.5 Django 1.6
Mit Django können wir ein Formular wie folgt deklarativ definieren:
# -*- coding: utf-8 -*- from django import forms class SimpleForm(forms.Form): field_a = forms.CharField(max_length=100) field_b = forms.CharField(max_length=100)
Schreiben Sie es sieht sehr komfortabel aus, aber das Problem tritt auf, wenn ich dieses Formular initialisiere, zum Beispiel:
from polls.forms import SimpleForm
sf = SimpleForm({'field_a':' value of field_a', 'field_b':'value of field_b'})
Führen Sie dann dir(sf) in der Python-Shell aus und stellen Sie fest, dass die Instanz nicht über die beiden Attribute field_a und field_b verfügt. Offensichtlich können wir sf nicht mögen .field_a bezieht sich auf die Felder auf sf. Aber natürlich können wir Formularfelder in der Vorlage in der Form {{ form_name.field_name }} referenzieren.
Nach einigen Nachforschungen stellte ich fest, dass der Implementierungsmechanismus dahinter ziemlich kompliziert ist. Wenn wir auf die Felder im Formular verweisen möchten, wie sollten wir es zunächst schreiben? Es sollte so geschrieben werden: sf['field_a']
Warum sollte es so geschrieben werden? Obiger Code, __getitem__-Methode von django.forms.BaseForm:
def __getitem__(self, name): "Returns a BoundField with the given name." try: field = self.fields[name] except KeyError: raise KeyError('Key %r not found in Form' % name) return BoundField(self, field, name)
Dadurch wird BaseForm in einen dict-ähnlichen Container umgewandelt, sodass Sie die obige Syntax verwenden können, um auf die Felder in zu verweisen bilden.
Es stellt sich wieder eine neue Frage: Warum können wir in der Vorlage auf Formularfelder in der Form {{ form_name.field_name }} verweisen? Siehe die offizielle Dokumentation von Django: https://docs.djangoproject.com/en/1.6/topics/templates/#variables. Es stellt sich heraus, dass die Vorlagen-Engine von Django, wenn sie auf einen Ausdruck wie {{ form_name.field_name }} trifft, eine Wörterbuchsuche für das form_name-Objekt ausführt. Wenn die Vorlagen-Engine also {{ sf.field_a }} auswertet, führt sie tatsächlich sf aus ['field_a'], die Wahrheit kam ans Licht.
Darüber hinaus ist der obige SimpleForm-Typ tatsächlich django.forms.DeclarativeFieldsMetaclass. Diese Metaklasse konvertiert tatsächlich alle mit deklarativer Syntax in SimpleForm deklarierten Felder (einschließlich deklarativer Felder in der übergeordneten Klasse) über die Methode get_declared_fields in ein Diktat und weist den Wert des Diktats dem zu generierenden Attribut base_fields zu und generiert es dann eine neue Klasse basierend auf SimpleForm.