Django ModelChoiceField允许创建对象 [英] Django ModelChoiceField allow objects creation
问题描述
Django的 ModelChoiceField
是使用 ModelForm
。验证后,该字段将检查所选值是否存在于相应的相关表中,如果不是这样,则提出 ValidationError
。
我正在创建一个文档
模型的表单,该模型具有类型
字段, 类型的外键,仅包含
名称
属性。为了清楚起见,这里是 models.py
的代码
class Type model.Model):
name = models.CharField(max_length = 32)
class文档(models.Model):
title = models.CharField(max_length = 256)
type = models.ForeignKey(Type,related_name ='related_documents')
选择
控件,我使用的是 selectize.js 为用户提供自动完成。此外,selectize提供了一个创建选项,允许在select中输入一个不存在的值。
我想扩展 ModelChoiceField
,以便在所选值不存在时创建新的类型
对象(新值将分配给 name
字段,这应该是可重用性的字段的选项)。如果可能,我希望对象不被插入到DB中,直到 save()
在验证的表单上调用(以防止多次失败的验证在db中创建多个行) 。在Django中这样做的好方法是什么?我试图查看文档和源代码,尝试覆盖 ModelChoiceField
,并尝试在 TextField
上构建此行为c>但我不知道是否有更简单的方法。
我研究了以下问题,但找不到答案。
- Django ModelChoiceField没有加号按钮
- Django:override RelatedFieldWidgetWrapper
- 如何在动态Django ModelChoiceField中设置初始值
I希望保持添加新类型的过程尽可能简单 - 即:不要使用附加到+按钮的弹出窗口。用户应该能够键入值,如果不存在,则创建该值。
谢谢
这似乎比没有使用ModelForm更容易。您可以创建一个所有类型
对象的列表,然后将其作为上下文变量传递给模板。然后,您可以使用该列表构造一个< select>
元素。然后使用jquery和 selectize
在窗体中添加必要的属性。
#views.py
...
types = Type.objects.all()
...
#template .html
...
< form action =method =POST> {%csrf_token%}
< input type ='text'name ='title'> ;
< select name ='type'id ='id_type'>
{%类型%}
< option value ={{type.id}}> {{type.name}}< / option>
{%endfor%}
< / select>
< input type ='submit'>
< / form>
< script type ='text / javascript'>
$('#id_type')。selectize({
create:true
});
< / script>
...
然后,当您提交表单时,您可以在简单的查看功能:
if request.method == POST:
/ pre>
title_post = request.POST.get('title ','')
type_post = request.POST.get('type',None)
如果type_post不是None:
try:
#如果选择了一个现有的类型我们将有一个ID来查找
type = Type.objects.get(id = type_post)
除了:
#如果查找失败,我们有一个用户输入的名称使用
type = Type.objects.create(name = type_post)
new_doc = Document.objects.create(title = title_post,type = type)
Django's
ModelChoiceField
is the default form field used for foreign keys when deriving a form from a model usingModelForm
. Upon validation, the field will check that selected value does exist in the corresponding related table, and raise aValidationError
if it is not the case.I'm creating a form for a
Document
model that has atype
field, a foreign key to aType
model which does only contain aname
attribute. Here is the code ofmodels.py
for clarityclass Type(models.Model): name = models.CharField(max_length=32) class Document(models.Model): title = models.CharField(max_length=256) type = models.ForeignKey(Type, related_name='related_documents')
Instead of a standard
select
control, I'm using selectize.js to provide auto-completion to the users. Moreover, selectize provides a "create" option, that allows to enter a value that does not exist yet into the select.I would like to extend the
ModelChoiceField
in order to create a newType
object when the selected value does not exist (the new value will be assigned toname
field, this should be an option of the field for reusability). If possible, I would like the object to not be inserted into DB untilsave()
is called on the validated form (to prevent that multiple failed validation create multiple rows in db). What would be a good way to do so in Django? I tried to look into the documentation and the source code, tried to overrideModelChoiceField
and tried to build this behavior basted on aTextField
but I'm not sure if there isn't a simpler way to do it.I looked into the following questions but couldn't find the answer.
- Django ModelChoiceField has no plus button
- Django: override RelatedFieldWidgetWrapper
- How to set initial value in a dynamic Django ModelChoiceField
I would like to keep the process of adding new types as simple as possible - i.e.: do not use a pop-up attached to a '+' button. User should be able to type the value, and the value gets created if it doesn't exist.
Thanks
This seems like it'd be easier without using a ModelForm. You could create a list of all of your Type
objects then pass that to the template as a context variable. Then, you could use that list to construct a <select>
element. Then use jquery and selectize
to add the necessary attributes to the form.
#views.py
...
types = Type.objects.all()
...
#template.html
...
<form action="" method="POST">{% csrf_token %}
<input type='text' name='title'>
<select name='type' id='id_type'>
{% for type in types %}
<option value="{{type.id}}">{{type.name}}</option>
{% endfor %}
</select>
<input type='submit'>
</form>
<script type='text/javascript'>
$('#id_type').selectize({
create: true
});
</script>
...
Then when you get a form submission, you can process it in a simple view function:
if request.method == POST:
title_post = request.POST.get('title','')
type_post = request.POST.get('type',None)
if type_post is not None:
try:
#If an existing Type was selected, we'll have an ID to lookup
type = Type.objects.get(id=type_post)
except:
#If that lookup failed, we've got a user-inputted name to use
type = Type.objects.create(name=type_post)
new_doc = Document.objects.create(title=title_post, type=type)
这篇关于Django ModelChoiceField允许创建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!