问题描述
我有两个具有外键关系的模型
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,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,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 %}
当我提交时,视图的post方法返回了form_invalid
我如何让 inline_formset 进行验证或者有更好的方法来做到这一点
解决方法
我更喜欢把这些视图写成函数,看起来更直接,试试:
@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})
我认为您必须考虑没有提供项目模型图片的情况。只需将两个表单都弹出到您的模板中,这应该可以工作。