1、如何在一对多和多对多字段后渲染 +
2、+对应的跳转路径是什么
3、保存添加记录同时,将原页面的对应的下拉菜单中添加该记录

open() 方法用于打开一个新的浏览器窗口或查找一个已命名的窗口。
JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+
重要事项:请不要混淆方法 Window.open() 与方法 Document.open(),这两者的功能完全不同。为了使您的代码清楚明白,请使用 Window.open(),而不要使用 open()。
window.open(URL,name,features,replace)
参数介绍:
URL:一个可选的字符串,声明了要在新窗口中显示的文档的 URL。如果省略了这个参数,或者它的值是空字符串,那么新窗口就不会显示任何文档。
name:一个可选的字符串,该字符串是一个由逗号分隔的特征列表,其中包括数字、字母和下划线,该字符声明了新窗口的名称。这个名称可以用作标记 <a> 和 <form> 的属性 target 的值。如果该参数指定了一个已经存在的窗口,那么 open() 方法就不再创建一个新窗口,而只是返回对指定窗口的引用。在这种情况下,features 将被忽略。
features:一个可选的字符串,声明了新窗口要显示的标准浏览器的特征。如果省略该参数,新窗口将具有所有标准特征。在窗口特征这个表格中,我们对该字符串的格式进行了详细的说明。
replace:一个可选的布尔值。规定了装载到窗口的 URL 是在窗口的浏览历史中创建一个新条目,还是替换浏览历史中的当前条目。支持下面的值:
true - URL 替换浏览历史中的当前条目。
false - URL 在浏览历史中创建新的条目。
channelmode=yes|no|1|0 是否使用剧院模式显示窗口。默认为 no。 directories=yes|no|1|0 是否添加目录按钮。默认为 yes。 fullscreen=yes|no|1|0 是否使用全屏模式显示浏览器。默认是 no。处于全屏模式的窗口必须同时处于剧院模式。 height=pixels 窗口文档显示区的高度。以像素计。 left=pixels 窗口的 x 坐标。以像素计。 location=yes|no|1|0 是否显示地址字段。默认是 yes。 menubar=yes|no|1|0 是否显示菜单栏。默认是 yes。 resizable=yes|no|1|0 窗口是否可调节尺寸。默认是 yes。 scrollbars=yes|no|1|0 是否显示滚动条。默认是 yes。 status=yes|no|1|0 是否添加状态栏。默认是 yes。 titlebar=yes|no|1|0 是否显示标题栏。默认是 yes。 toolbar=yes|no|1|0 是否显示浏览器的工具栏。默认是 yes。 top=pixels 窗口的 y 坐标。 width=pixels 窗口的文档显示区的宽度。以像素计。
<body>
<p><button class="add" onclick="foo()">+</button></p>
<script>
function foo() {
window.open("/addbook/", "", "width=400,height=400,top=100,left=200")
}
</script>
</body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div style="position: relative">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
<a href="" style="position: absolute; right: -30px; top: 20px;"><span style="font-size: 28px">+</span></a>
</div>
{% endfor %}
<button type="submit" class="btn btn-default pull-right">提交</button>
</form>
</div>
</div>
</div>
注意:
父辈元素设置相对定位,子元素设置绝对定位,那么会以父辈元素左上角为参考点。
因此在这里a标签以父级盒子div标签为参考点。top属性时,以父盒子左上角为参考点调整位置。

这个组件的功能就是把model和form组合起来。查看分析service/stark.py代码如下:
class ModelStark(object):
"""默认类,定制配置类"""
def get_modelform_class(self):
"""用来获取modelform类"""
if not self.modelform_class:
# 如果没有值
from django.forms import ModelForm
from django.forms import widgets as wid
class ModelFormDemo(ModelForm):
class Meta:
model = self.model
fields = "__all__"
return ModelFormDemo
else:
# 如果有值说明在用户已经自己定制过了,直接取值
return self.modelform_class
def add_view(self, request):
"""添加页面视图"""
ModelFormDemo = self.get_modelform_class()
form = ModelFormDemo() # 实例化步骤提前不管是post请求还是get请求都会传递到模板中
if request.method == "POST":
form = ModelFormDemo(request.POST)
if form.is_valid(): # 校验字段全部合格
form.save()
return redirect(self.get_list_url()) # 跳转到当前访问表的查看页面
# 校验有错误返回页面,且包含了错误信息
return render(request, "add_view.html", locals())
ModelFormDemo是ModelForm的子类,form是ModelFormDemo实例对象。分析这个form对象:
for bound_field in form: # 拿到每一个字段
# print(type(bound_field)) # <class ‘django.forms.boundfield.BoundField‘> django封装的数据
# 通过这种方式查看这个数据类:from django.forms.boundfield import BoundField
print(bound_field.field)
print(type(bound_field.field))
"""
<django.forms.fields.CharField object at 0x10d73a160>
<class ‘django.forms.fields.CharField‘>
<django.forms.fields.DateField object at 0x10d73a1d0>
<class ‘django.forms.fields.DateField‘>
<django.forms.fields.DecimalField object at 0x10d73a240>
<class ‘django.forms.fields.DecimalField‘>
<django.forms.models.ModelChoiceField object at 0x10d73a2b0>
<class ‘django.forms.models.ModelChoiceField‘>
<django.forms.models.ModelMultipleChoiceField object at 0x10d73a320>
<class ‘django.forms.models.ModelMultipleChoiceField‘>
"""
可以看到它的类型是<class ‘django.forms.boundfield.BoundField‘>一种django的封装数据。查看BoundField类可知它具有field属性。
可以看出这个field属性的类型是CharField、ModelChoiceField、ModelMultipleChoiceField等Django内置字段类型。
在forms组件中,ChoiceField是负责渲染select标签的;ModelChoiceField继承ChoiceField常用于渲染一对多的select标签;ModelMultipleChoiceField继承ModelChoiceField常用于渲染多对多的select标签。
service/stark.py:
class ModelStark(object):
"""默认类,定制配置类"""
def add_view(self, request):
"""添加页面视图"""
ModelFormDemo = self.get_modelform_class()
form = ModelFormDemo() # 实例化步骤提前不管是post请求还是get请求都会传递到模板中
for bound_field in form: # 拿到每一个字段
print(bound_field.field)
print(type(bound_field.field))
from django.forms.models import ModelChoiceField # ModelMultipleChoiceField继承ModelChoiceField
if isinstance(bound_field.field, ModelChoiceField): # 通过这个判断是否是一对多或多对多的字段对象
bound_field.is_pop = True # 给所有一对多、多对多对象添加is_pop这个属性
if request.method == "POST":
form = ModelFormDemo(request.POST)
if form.is_valid(): # 校验字段全部合格
form.save()
return redirect(self.get_list_url()) # 跳转到当前访问表的查看页面
# 校验有错误返回页面,且包含了错误信息
return render(request, "add_view.html", locals())
注意:ModelMultipleChoiceField是ModelChoiceField的子类,因此只要引入ModelChoiceField,判断bound_field.field是否是ModelChoiceField的对象就可以判断是否是一对一或一对多字段。其次通过bound_field.is_pop = True的方式为bound_filed对象添加属性。在form页面中可以通过判断字段对象的is_pop属性是否为真判断是否需要添加“+”。
form.html:
-------代码部分省略
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div style="position: relative">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
{% if field.is_pop %}
{# 判断是一对多、多对多字段 #}
<a href="" style="position: absolute; right: -30px; top: 20px;"><span style="font-size: 28px">+</span></a>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-default pull-right">提交</button>
</form>
显示效果:

原文:https://www.cnblogs.com/xiugeng/p/9532592.html