modelformset_factory ไม่บันทึกอินสแตนซ์ลงในฐานข้อมูล

ฉันกำลังพยายามสร้าง formset ด้วยอินสแตนซ์บนเพจของฉัน แต่ formset ไม่บันทึกอินสแตนซ์เลย การบันทึกช่องเพิ่มเติมทำงานได้ดี แต่ฉันไม่สามารถเข้าใจข้อผิดพลาดกับอินสแตนซ์ได้ ฉันมีแบบฟอร์มมากมายในหน้านี้ และนี่คือแบบฟอร์มสุดท้ายที่ไม่บันทึก: มุมมองของฉัน:

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 อินสแตนซ์และอีกหนึ่งฟิลด์พิเศษ ถ้าฉันคลิกฟิลด์ส่งที่แล้ว มีอินสแตนซ์ไม่เปลี่ยนแปลงในฐานข้อมูลและในหน้า หากฉันเปลี่ยนมุมมอง is_valid: เป็น is_valid(): ดูเหมือนว่าแบบฟอร์มจะบันทึกบนหน้า แต่ไม่อยู่ในฐานข้อมูล ดังนั้นหากฉันไปที่หน้าอื่นแล้วกลับมา จะไม่มีอะไรถูกบันทึกไว้ หากฉันลบตรรกะทั้งหมดในมุมมองของฉันออกไป มันก็ทำงานในลักษณะเดียวกัน และฉันไม่รู้จริงๆ ว่าฉันทำอะไรผิด โปรดช่วยด้วย!


person Andrej Vilenskij    schedule 11.12.2018    source แหล่งที่มา


คำตอบ (1)


ปัญหาคือคุณควรโทร instance.save() แทนที่จะเป็น ftppath.save() ที่ท้ายลูป

โปรดทราบว่า is_valid เป็นวิธีการ คุณต้องเรียกมันว่า: if ftppath.is_valid():

และโปรดทราบด้วยว่า การเก็บตัวนับแบบนั้นและเพิ่มค่าด้วยตนเองนั้นไม่ใช่เรื่อง Pythonic มากนัก ให้ใช้ enumerate แทน

แต่จริงๆ แล้ว คุณคงไม่อยากใช้อันใดอันหนึ่งอยู่แล้ว แทนที่จะรับข้อมูลจาก POST โดยการเชื่อม ID ของแบบฟอร์ม คุณควรได้รับจากแบบฟอร์ม 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 จึงควรตั้งค่าให้คุณแล้ว

person Daniel Roseman    schedule 11.12.2018
comment
ขอบคุณมากสำหรับคำแนะนำของคุณเกี่ยวกับวิธีทำให้โค้ดของฉันดีขึ้นและคำตอบของคุณ ปัญหาทั้งหมดอยู่ในฟิลด์ id ซึ่งจำเป็นบนหน้าสำหรับแต่ละแบบฟอร์มใน formset นั่นเป็นสาเหตุที่ formset ไม่สามารถผ่านการตรวจสอบได้ - person Andrej Vilenskij; 11.12.2018