Django 加上“选择”;“自我”;添加窗体上的自引用外键
我有一个自我参照的外键字段:Django 加上“选择”;“自我”;添加窗体上的自引用外键,django,django-forms,foreign-keys,self-reference,Django,Django Forms,Foreign Keys,Self Reference,我有一个自我参照的外键字段: class Thing(models.Model) special_thing = models.ForeignKey( 'self', blank=True, null=True ) 在“添加内容”窗体上,除了其他现有内容外,我需要提供一个选项“此内容本身”,即尚未添加的内容。告诉用户添加然后重新访问该字段不是一个选项 我该怎么做 我目前的想法是覆盖表单: 将“special_thing”从默认模
class Thing(models.Model)
special_thing = models.ForeignKey(
'self',
blank=True,
null=True
)
在“添加内容”窗体上,除了其他现有内容外,我需要提供一个选项“此内容本身”,即尚未添加的内容。告诉用户添加然后重新访问该字段不是一个选项
我该怎么做
我目前的想法是覆盖表单:
- 将“special_thing”从默认模型ChoiceField更改为ChoiceField
- 将新的特殊(“标记”)选项“***这个东西***”添加到_uinit__()中的字段选项中
- 提供clean_special_thing(),它允许“***THIS thing***”或可以从查询集查找的对象的id
- 在save()中,如果选择了“***THIS THING***”,则使用special_THING=None保存THING,然后将其设置为自身并再次保存。否则,按给定的id查找对象,并像往常一样保存
我这样做是为了ModelAdmin的ModelForm。有更简单的方法吗?另一种可能的解决方案是使用jQuery()将另一个
***这个东西***
添加到模板中的formfield
提交表单后,您可以在表单的clean
-方法或视图中选中所选选项来存储表单
例如:
if request.POST:
if request.POST['special_thing'] == 'myself':
# do whatever should be done
...
我一直在思考这些问题,最后一步是没有必要的。相反,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
六羟甲基三聚氰胺六甲醚。。。问题是“应该做什么”就是将instance.special\u thing设置为指向对象本身,而这对于clean()来说还为时过早。根据我的回答,clean()实际上能够将instance.special\u thing设置为实例,即使在这一点上没有pk。添加新选项非常简单,我将其保留在服务器端,并将所有内容都放在一个地方。