【问题标题】:Why is the inline formset not validating为什么内联表单集不验证
【发布时间】:2021-09-23 17:27:40
【问题描述】:

我有两个具有外键关系的模型

models.py

from django.db import models

# Create your models here.
class Project(models.Model):
    STATUSES = (
        ('Ongoing', 'Ongoing'),
        ('Completed', 'Completed')
    )

    YEARS = (
        (2019, 2019),
        (2020, 2020),
        (2021, 2021),
        (2022, 2022)
    )
    
    name = models.CharField(max_length=200)
    client = models.CharField(max_length=100)
    year = models.SmallIntegerField(choices=YEARS)
    status = models.CharField(max_length=10, choices=STATUSES)
    picture = models.ImageField(blank=True, null=True)
    description = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.name


class Photo(models.Model):
    project = models.ForeignKey("Project", on_delete=models.CASCADE, related_name="images", blank=True, null=True)
    image = models.ImageField()
    description = models.CharField(max_length=100, blank=True, null=True)
    slide = models.BooleanField(default=False)

我希望在同一个表单上创建照片和项目,所以我使用了 inline_formset_factory

forms.py

from django.forms import inlineformset_factory
from projects.models import Photo, Project
from django.forms import ModelForm


class ProjectModelForm(ModelForm):
    class Meta:
        model = Project
        fields = (
            'name',
            'client',
            'year',
            'picture',
            'status',
            'description',
        )


class PhotoModelForm(ModelForm):
    class Meta:
        model = Photo
        fields = (
            'image',
            'slide',
            'description'
        )


PhotoFormset = inlineformset_factory(Project, Photo, form=PhotoModelForm, extra=1)

我使用了通用的 CreateView

views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from projects.forms import PhotoFormset, ProjectModelForm
from django.shortcuts import redirect, reverse, render
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Photo, Project

# Create your views here.
class ProjectCreateView(LoginRequiredMixin, CreateView):
    template_name = 'projects/project_create.html'
    form_class = ProjectModelForm

    def get_context_data(self, **kwargs):
        context = super(ProjectCreateView, self).get_context_data(**kwargs)
        context['photos_formset'] = PhotoFormset()
        return context
    
    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        photo_formset = PhotoFormset(self.request.POST)
        if form.is_valid() and photo_formset.is_valid():
            return self.form_valid(form, photo_formset)
        else:
            return self.form_invalid(form, photo_formset)
    
    def form_valid(self, form, photo_formset):
        self.object = form.save(commit=False)
        self.object.save()
        print('valid')
        photos = photo_formset.save(commit=False)
        for photo in photos:
            photo.project = self.object
            photo.save()
        return reverse('projects:projectspage')

    def form_invalid(self, form, photo_formset):
        if not photo_formset.is_valid():
            print('invalid formset')
        return self.render_to_response(
            self.get_context_data(form=form, photos_formset=photo_formset)
        )

    def get_success_url(self):
        return reverse('projects:projectspage')

这是模板

{% extends 'base.html' %}
{% load crispy_forms_filters %}
<!-- crispy_forms_tags -->

{% block content %}
    <div class="container">
        <h2>create new project</h2>
        <form method="post">
            {% csrf_token %}
            {{ form|crispy }}
            <h2 class="display-6 my-5">
                Add photos
            </h2>
            {{ photos_formset.as_p }}
            <input type="submit" value="Create" class="btn btn-primary">
        </form>
    </div>
{% endblock content %}

当我提交form_invalid时从视图的post方法返回

我如何让 inline_formset 验证或有更好的方法来做它

【问题讨论】:

    标签: python django django-views django-forms inline-formset


    【解决方案1】:

    我更喜欢把这些视图写成函数,看起来更直接,试试:

    @login_required
    def post_news(request):
        if request.method == 'POST':
            project_form = ProjectModelForm(request.POST, request.FILES)
            photo_form = PhotoModelForm(request.POST, request.FILES)
            picture = request.FILES['picture']
            image = request.FILES['image']
            if project_form.is_valid() and photo_form.is_valid():
                project_instance = project_form.save(commit=False)
                project_instance.picture = picture
                project_instance.save()
                photo_instance = project_form.save(commit=False)
                photo_instance.project = project_instance
                photo_instance.image = image
                photo_instance.save()                
    
                return reverse('projects:projectspage')
    else:
        project_form = ProjectModelForm()
        photo_form = PhotoModelForm()
    
    return render(request, 'projects/project_create.html',
                  {'project_form': project_form, 'photo_form': photo_form})
    

    我认为,当没有提供项目模型的图片时,您将不得不考虑这种情况。只需将两个表单都弹出到您的模板中,这应该可以工作。

    【讨论】:

    • 我在 /projects/create/ 'picture' 得到一个 MultiValueDictKeyError
    • 对了,你需要在模板文件的form标签里有enctype="multipart/form-data"。
    • 伟大的图片现在在帖子中,但我得到一个属性错误,。 “str”对象没有属性“get”
    • 请编辑您的帖子并添加整个错误回溯。
    猜你喜欢
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 2011-09-17
    • 2013-09-03
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多