modelformset_factory 不将实例保存到数据库
modelformset_factory doesnt save instances to database
我试图在我的页面上创建一个带有实例的表单集,但表单集根本不保存实例。额外的字段保存效果很好,但我无法理解实例有什么问题。我在页面上有很多表格,这是最后一个,没有保存:
我的看法:
def details(request, username, slug):
sm = Social_media.objects.all()
profile = get_object_or_404(Profiles, user__username=username)
site = get_object_or_404(MySites, slug=slug, user__username=username)
ftp = get_object_or_404(FTP, site=site)
FtpPathFormSet = forms.modelformset_factory(FtpPath,form=FtpPathForm,extra=1)
sjim_ops = SjimOperations.objects.filter(user=request.user).order_by('-date')
sjim_det = SjimDetails.objects.all()
if request.method == 'POST':
// other forms and logic
if 'change3' in request.POST:
newsite = NewSiteForm(instance=site)
newftp = NewFtpForm(instance=ftp)
ftppath = FtpPathFormSet(request.POST)
if ftppath.is_valid:
print('here')
i = 0
instances = ftppath.save(commit=False)
for instance in instances:
print('here2')
instance.ftp = ftp
instance.recursive = request.POST.get('form-'+str(i)+'-recursive')
if instance.recursive == 'on':
instance.recursive = True
else:
instance.recursive = False
instance.period = request.POST.get('form-'+str(i)+'-period')
try:
testconnect = ftplibr(ftp.host)
testconnect.login(user=ftp.ftpuser, passwd=ftp.password)
testconnect.cwd(instance.path)
instance.find = True
testconnect.quit()
except:
instance.find = False
ftppath.save()
i =+ 1
return redirect('main:details', username=username, slug=site.slug)
型号:
class FtpPath(models.Model):
period = (
('Раз в сутки','Раз в сутки'),
('Раз в неделю','Раз в неделю'),
('Раз в 2 недели','Раз в 2 недели')
)
ftp = models.ForeignKey(FTP, on_delete=models.CASCADE)
path = models.CharField(max_length=200, blank=True)
period = models.CharField(choices=period, max_length=20, null=True, blank=True)
find = models.BooleanField(null=True, default=False)
recursive = models.BooleanField(null=True, default=False)
class Meta:
verbose_name = 'FTP path'
verbose_name_plural = 'FTP paths'
表格:
class FtpPathForm(forms.ModelForm):
path = forms.CharField(widget=forms.TextInput(attrs={'type':'text','class':'effect-16'}), required=False)
recursive = forms.BooleanField(widget=forms.CheckboxInput(attrs={}), required=False)
period = forms.CharField(widget=forms.TextInput(attrs={'type':'text','style':'display:none','class':'period-input'}), required=False, label='')
class Meta:
model = FtpPath
fields = ('path', 'recursive','period', 'find')
模板:
<form method="POST" id="path-form">
{% csrf_token %}
{{ ftppath.management_form }}
<div class="info_tab_3col">
<div class="form_title">Выбрать папки</div>
<div class="form_folders">
{% for ftppath in ftppath %}
{% if ftppath.find.value == True %}
<div class="form_folder">
{% else %}
<div class="form_folder form_folder_error">
{% endif %}
<div class="ftp_form_item">
<div class="ftp_f_long ftp_f_long_i">
<div class="input-effect">
{{ ftppath.path }}
<label>Путь на сервере</label>
<span class="focus-border"></span>
</div>
</div>
<div class="ftp_form_s ftp_form_s_i">
<div class="checkbox_box">
{{ ftppath.recursive }}
<label for="id_form-{{ forloop.counter0 }}-recursive">
<span><!-- This span is needed to create the "checkbox" element --></span>
Рекурсивно
</label>
</div>
</div>
</div>
<div class="ftp_form_item ftp_form_item_type">
<div class="select_wrapper">
{{ ftppath.period }}
<div class="select_wrapper_val"></div>
<span class="select_wrapper_label">Период</span>
<span class="input_error error-ftppath"></span>
<div class="select_list">
<div class="select_list_item">Раз в сутки</div>
<div class="select_list_item">Раз в неделю</div>
<div class="select_list_item">Раз в 2 недели</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="form_button form_button_ftp">
<button class="btn" type="submit" name="change3">
<span>Изменить</span>
</button>
</div>
</div>
</form>
所以 formset 在页面上呈现正常:我 1 instance and one extra field. 如果我单击提交字段,该字段已经在数据库和页面上没有更改实例。如果我将我的视图 is_valid:
更改为 is_valid():
,看起来表单保存在页面上,而不是数据库中,所以如果我转到其他页面并返回,则不会保存任何内容。如果我删除我认为的所有逻辑,它的工作方式相同,我不知道我做错了什么,请帮忙!
问题是您应该在循环结束时调用 instance.save()
而不是 ftppath.save()
。
另外注意is_valid
是方法,需要调用:if ftppath.is_valid():
另请注意,保持这样的计数器并手动递增它是非常不符合 Python 风格的。相反,使用 enumerate
.
但实际上,您无论如何都不想使用其中任何一个;不要通过连接表单 ID 从 POST 获取数据,您应该从表单 cleaned_data 本身获取数据。如果这样做,则无需手动将其与 "on" 进行比较;这就是表单清理过程 已经为您完成的工作 。
所以你应该遍历表单,然后保存每一个:
if ftppath.is_valid():
for form in ftppath.forms:
instance = form.save(commit=False)
instance.ftp = ftp
instance.recursive = form.cleaned_data['recursive']
instance.period = form.cleaned_data['period']
try:
...
except ftplib.all_errors: # always use a specific error
...
instance.save()
最后,您确定需要手动设置这两个值吗?它们是模型上的字段并在表单的字段属性中指定,因此 Django 应该已经为您设置了它们。
我试图在我的页面上创建一个带有实例的表单集,但表单集根本不保存实例。额外的字段保存效果很好,但我无法理解实例有什么问题。我在页面上有很多表格,这是最后一个,没有保存: 我的看法:
def details(request, username, slug):
sm = Social_media.objects.all()
profile = get_object_or_404(Profiles, user__username=username)
site = get_object_or_404(MySites, slug=slug, user__username=username)
ftp = get_object_or_404(FTP, site=site)
FtpPathFormSet = forms.modelformset_factory(FtpPath,form=FtpPathForm,extra=1)
sjim_ops = SjimOperations.objects.filter(user=request.user).order_by('-date')
sjim_det = SjimDetails.objects.all()
if request.method == 'POST':
// other forms and logic
if 'change3' in request.POST:
newsite = NewSiteForm(instance=site)
newftp = NewFtpForm(instance=ftp)
ftppath = FtpPathFormSet(request.POST)
if ftppath.is_valid:
print('here')
i = 0
instances = ftppath.save(commit=False)
for instance in instances:
print('here2')
instance.ftp = ftp
instance.recursive = request.POST.get('form-'+str(i)+'-recursive')
if instance.recursive == 'on':
instance.recursive = True
else:
instance.recursive = False
instance.period = request.POST.get('form-'+str(i)+'-period')
try:
testconnect = ftplibr(ftp.host)
testconnect.login(user=ftp.ftpuser, passwd=ftp.password)
testconnect.cwd(instance.path)
instance.find = True
testconnect.quit()
except:
instance.find = False
ftppath.save()
i =+ 1
return redirect('main:details', username=username, slug=site.slug)
型号:
class FtpPath(models.Model):
period = (
('Раз в сутки','Раз в сутки'),
('Раз в неделю','Раз в неделю'),
('Раз в 2 недели','Раз в 2 недели')
)
ftp = models.ForeignKey(FTP, on_delete=models.CASCADE)
path = models.CharField(max_length=200, blank=True)
period = models.CharField(choices=period, max_length=20, null=True, blank=True)
find = models.BooleanField(null=True, default=False)
recursive = models.BooleanField(null=True, default=False)
class Meta:
verbose_name = 'FTP path'
verbose_name_plural = 'FTP paths'
表格:
class FtpPathForm(forms.ModelForm):
path = forms.CharField(widget=forms.TextInput(attrs={'type':'text','class':'effect-16'}), required=False)
recursive = forms.BooleanField(widget=forms.CheckboxInput(attrs={}), required=False)
period = forms.CharField(widget=forms.TextInput(attrs={'type':'text','style':'display:none','class':'period-input'}), required=False, label='')
class Meta:
model = FtpPath
fields = ('path', 'recursive','period', 'find')
模板:
<form method="POST" id="path-form">
{% csrf_token %}
{{ ftppath.management_form }}
<div class="info_tab_3col">
<div class="form_title">Выбрать папки</div>
<div class="form_folders">
{% for ftppath in ftppath %}
{% if ftppath.find.value == True %}
<div class="form_folder">
{% else %}
<div class="form_folder form_folder_error">
{% endif %}
<div class="ftp_form_item">
<div class="ftp_f_long ftp_f_long_i">
<div class="input-effect">
{{ ftppath.path }}
<label>Путь на сервере</label>
<span class="focus-border"></span>
</div>
</div>
<div class="ftp_form_s ftp_form_s_i">
<div class="checkbox_box">
{{ ftppath.recursive }}
<label for="id_form-{{ forloop.counter0 }}-recursive">
<span><!-- This span is needed to create the "checkbox" element --></span>
Рекурсивно
</label>
</div>
</div>
</div>
<div class="ftp_form_item ftp_form_item_type">
<div class="select_wrapper">
{{ ftppath.period }}
<div class="select_wrapper_val"></div>
<span class="select_wrapper_label">Период</span>
<span class="input_error error-ftppath"></span>
<div class="select_list">
<div class="select_list_item">Раз в сутки</div>
<div class="select_list_item">Раз в неделю</div>
<div class="select_list_item">Раз в 2 недели</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="form_button form_button_ftp">
<button class="btn" type="submit" name="change3">
<span>Изменить</span>
</button>
</div>
</div>
</form>
所以 formset 在页面上呈现正常:我 1 instance and one extra field. 如果我单击提交字段,该字段已经在数据库和页面上没有更改实例。如果我将我的视图 is_valid:
更改为 is_valid():
,看起来表单保存在页面上,而不是数据库中,所以如果我转到其他页面并返回,则不会保存任何内容。如果我删除我认为的所有逻辑,它的工作方式相同,我不知道我做错了什么,请帮忙!
问题是您应该在循环结束时调用 instance.save()
而不是 ftppath.save()
。
另外注意is_valid
是方法,需要调用:if ftppath.is_valid():
另请注意,保持这样的计数器并手动递增它是非常不符合 Python 风格的。相反,使用 enumerate
.
但实际上,您无论如何都不想使用其中任何一个;不要通过连接表单 ID 从 POST 获取数据,您应该从表单 cleaned_data 本身获取数据。如果这样做,则无需手动将其与 "on" 进行比较;这就是表单清理过程 已经为您完成的工作 。
所以你应该遍历表单,然后保存每一个:
if ftppath.is_valid():
for form in ftppath.forms:
instance = form.save(commit=False)
instance.ftp = ftp
instance.recursive = form.cleaned_data['recursive']
instance.period = form.cleaned_data['period']
try:
...
except ftplib.all_errors: # always use a specific error
...
instance.save()
最后,您确定需要手动设置这两个值吗?它们是模型上的字段并在表单的字段属性中指定,因此 Django 应该已经为您设置了它们。