Reputation: 517
Im trying to make a formset with instances on my page, but formset dont saving instances at all. Extra fields saving is working well, but i cant get whats wrong with instances. I have a lot of forms on the page, and this is the last one, that not saving: My view:
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)
model:
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'
Form:
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')
template:
<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>
So formset is rendering ok on page: i have 1 instance and one extra field. If i click submit field that already have instance dont changing in database and on page. If i changing in my view is_valid:
to is_valid():
, it looks like form saves on page, but not in database, so if i go to other page, and come back, nothing will be saved. If i remove all logic in my view, it works the same way, and i dont know really what i doing wrong, please help!
Upvotes: 0
Views: 469
Reputation: 599630
The problem is that you should call instance.save()
instead of ftppath.save()
at the end of your loop.
Also note that is_valid
is a method, you need to call it: if ftppath.is_valid():
And also also note, it's very unPythonic to keep a counter like that and increment it manually. Instead, use enumerate
.
But actually, you don't want to use either of those anyway; instead of getting the data from the POST by concatenating the form ID, you should get it from the form cleaned_data itself. If you do that, then you don't need to manually compare it with "on"; that's what the form clean process already does for you.
So you should iterate over the forms, then save each one:
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()
Finally though, are you sure you need to even set those two values manually? They are fields on the model and specified in the form's fields attribute, so Django should already be setting them for you.
Upvotes: 1