私はそれらの考えに沿って進んでおり、最後のステップは必要ありません. 代わりに、clean メソッドは選択肢をフォームのインスタンスに設定でき、全体的な労力は非常に合理的なままです。
from django.contrib import admin
from django import forms
from mdoels import Thing
MARKER_THIS_THING = '*** THIS THING ***'
class ThingAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
"""
Return the Thing ModelForm with an additional choice for the
'special_thing' field (FK to self) that allows the Add Thing form
to refer to the newly added instance itself.
"""
form = super(ThingAdmin, self).get_form(request, obj, **kwargs)
# The form still has a ModelChoiceField for special_thing, construct
# new non-model choices from that so we can add the 'this thing' choice
thing_choices = [c for c in form.base_fields['special_thing'].choices]
if not obj:
# Only the Add form needs the special choice
thing_choices = [(MARKER_THIS_THING, MARKER_THIS_THING)] + thing_choices
form.base_fields['special_thing'] = forms.ChoiceField(
choices=thing_choices
)
def clean_special_thing(form):
"""
Now just a simple ChoiceField, convert posted values to
model instances like a ModelChoiceField does.
Convert special new 'this thing' choice to be the newly added
instance.
"""
data = form.cleaned_data['special_thing']
instance = getattr(form, 'instance', None)
if data==MARKER_THIS_THING and not (instance and instance.pk):
# Referring to new instance itself on Add form
return instance
# Return selected model like a ModelChoiceField does
try:
data = Thing.objects.get(pk=data)
except Thing.DoesNotExist:
raise forms.ValidationError('Invalid choice')
return data
# clean_* are not part of ModelAdmin, just of forms and models.
# So we attach it to the form:
form.clean_special_thing = clean_special_thing
return form