Django Crispy表单提交后数据无法保存及渲染问题求助
如何保存Django Crispy表单中的数据?
问题描述
点击表单提交按钮后,进入帖子渲染页面却看不到刚创建的帖子。表单样式如下:
相关代码
表单页面:anzeige_new.html
{% load crispy_forms_tags %} {% block content %} <div class="content-section"> <form method="POST"> {% csrf_token %} <fieldset class="form-group"> <legend class="border-bottom mb-4">创建广告</legend> {{ form|crispy }} </fieldset> <div class="form-group"> <button class="btn btn-outline-info" type="submit">发布</button> </div> </form> </div> {% endblock content %}
帖子渲染页面(初始版本):angebote.html
{% block content %} {% for post in posts %} <p>进入循环</p> <a class="mr-2" href="#">{{ Post.objects.all }}</a> <article class="media content-section"> <img class="rounded-circle article-img" src="{{ post.author.profile.image.url"> <div class="media-body"> <div class="article-metadata"> <a class="mr-2" href="#">{{ post.author }}</a> <small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small> </div> <h2><a class="article-title">{{ post.title }}</a></h2> <p class="article-content">{{ post.content }}</p> </div> </article> {% endfor %} {% endblock content %}
forms.py
class PostForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(PostForm, self).__init__(*args, **kwargs) # 给表单实例传入FormHelper,自动生成默认布局 self.helper = FormHelper(self) # 动态添加提交按钮 self.helper.layout.append(Submit('save', 'save')) class Meta: model = Post fields = ('title', 'category', 'weekday')
models.py
class Post(models.Model): title = models.CharField(max_length=100) date_posted = models.DateTimeField(default=timezone.now) author = models.ForeignKey(User, on_delete=models.CASCADE, default=1) post = models.CharField(max_length=100, default='SOME STRING') weekday_choices = ( ('Monday', 'Monday'), ('Tuesday', 'Tuesday'), ('Wednesday', 'Wednesday'), ('Thursday', 'Thursday'), ('Friday', 'Friday'), ('Saturday', 'Saturday'), ('Sunday', 'Sunday'), ) weekday = models.CharField(max_length=15, choices=weekday_choices, default=0) def __str__(self): return self.title def get_absolute_url(self): return reverse('post-detail', kwargs={'pk': self.pk})
views.py(初始版本)
class PostCreateView(LoginRequiredMixin, CreateView): model = Post fields = ['title', 'category', 'weekday'] def form_valid(self, form): form.instance.author = self.request.user return super().form_valid(form) class PostListView(ListView): model = Post template_name = 'vereinsapp/angebote.html' # <app>/<model>_<viewtype>.html context_object_name = 'posts' ordering = ['-date_posted'] # 帖子按最新到最旧排序 class CreateView(TemplateView): template_name = 'vereinsapp/anzeige_new.html' print("Inside Create View") def post(self, request): form = PostForm(request.POST) if form.is_valid(): text = form.cleaned_data['post'] post = form.save() post.save() form = PostForm() post = form.save() return redirect('post:posts') args = {'form': form} return render(request, self.template_name, args)
urls.py
urlpatterns = [ path('', views.index, name='index'), path('vereinsapp/', views.index, name='index'), path('angebote/', views.angebote), path('angebotsprofil/', views.angebotsprofil), path('vereinsmarketing/', views.vereinsmarketing), path('anzeige_new/', views.anzeige_new), path('nutzerprofil/', views.nutzerprofil), path('posts/', PostListView.as_view(), name='posts'), path('post/new/', PostCreateView.as_view(), name='post-create'), path('post/<int:pk>/update/', PostUpdateView.as_view(), name='post-update'), path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'), path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'), ]
更新后的代码
PostListView(views.py)
class PostListView(ListView): model = Post template_name = 'vereinsapp/angebote.html' # <app>/<model>_<viewtype>.html context_object_name = 'posts' ordering = ['-date_posted'] # 帖子按最新到最旧排序 queryset = Post.objects.all()
帖子渲染页面(更新后):angebote.html
{% block content %} {% for post in posts %} <p>进入循环</p> <a class="mr-2" href="#">{{ post }}</a> <article class="media content-section"> <img class="rounded-circle article-img" src="{{ post.author.profile.image.url"> <div class="media-body"> <div class="article-metadata"> <a class="mr-2" href="#">{{ post.author }}</a> <small class="text-muted">{{ post.weekday }}</small> </div> <h2><a class="article-title">{{ post.title }}</a></h2> <p class="article-content">{{ post.category }}</p> </div> </article> {% endfor %} {% endblock content %}
问题排查与解决
核心问题1:表单提交路径不匹配
你的表单页面anzeige_new.html对应的URL是anzeige_new/,绑定的视图是views.anzeige_new,但自定义的CreateView并未被使用。真正处理创建逻辑的PostCreateView对应URL是post/new/,这意味着当前提交的表单根本没走正确的创建视图,数据自然不会保存。
解决:
- 要么修改表单的
action属性,指向正确的创建视图:<form method="POST" action="{% url 'post-create' %}"> - 要么将
urls.py中anzeige_new/的视图改为自定义CreateView(更推荐用Django自带的PostCreateView)。
核心问题2:自定义CreateView逻辑错误
自定义CreateView有多处问题:
- 尝试获取
form.cleaned_data['post'],但PostForm并未包含post字段(表单字段是title、category、weekday),会直接抛出KeyError。 - 保存表单后重新实例化空表单并再次保存,相当于创建了一个空Post对象,完全多余。
- 重定向的
'post:posts'命名空间不存在,URL中posts的name是'posts',应改为redirect('posts')。
如果要使用自定义视图,修正后代码如下:
class CreateView(TemplateView): template_name = 'vereinsapp/anzeige_new.html' def get(self, request): form = PostForm() return render(request, self.template_name, {'form': form}) def post(self, request): form = PostForm(request.POST) if form.is_valid(): post = form.save(commit=False) # 先不保存到数据库 post.author = request.user # 手动设置作者 post.save() # 保存到数据库 return redirect('posts') return render(request, self.template_name, {'form': form})
核心问题3:模型与模板字段不匹配
Post模型中没有category字段,但表单和模板都用到了该字段,会导致表单验证失败或模板渲染错误。需在models.py中添加:category = models.CharField(max_length=100) # 可根据需求调整字段类型和参数- 模板中
{{ post.author.profile.image.url }}缺少闭合的}},修正为:{{ post.author.profile.image.url }}
其他问题
Post模型中weekday的default=0错误,选项是字符串类型(如'Monday'),应设置默认值为选项中的一个,比如default='Monday'。PostListView里的queryset = Post.objects.all()多余,model = Post已默认获取所有对象。
总结修正步骤
- 在
models.py中添加category字段,修正weekday的默认值。 - 确保表单提交到正确的视图(使用
PostCreateView或修正自定义CreateView)。 - 修正模板中的语法错误和字段匹配问题。
- 检查视图中的重定向和表单处理逻辑,确保数据正确保存到数据库。
内容的提问来源于stack exchange,提问作者mx1txm
相关产品推荐
相关产品推荐

