You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ArticlePostUpdateView未向更新模板传数据,slug为空求助

问题描述

论坛帖子更新功能正常,但文章更新功能失效:article_update_form 模板无法从视图接收数据,导致slug为空;手动通过get_context_data传递post到模板后,表单又无法渲染forms.py中的组件。

模型代码

class ArticlePost(models.Model):
    title = models.CharField(max_length=400)
    slug = models.CharField(max_length=400, unique=True, blank=True)
    article_users = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="article_users")
    content = models.TextField()
    categories = models.ManyToManyField(ArticleCategory)
    date = models.DateTimeField(auto_now_add=True)
    approved = models.BooleanField(default=False)
    hit_count_generic = GenericRelation(HitCount, object_id_field="object_pk",
                                        related_query_name="hit_count_generic_relation")
    article_tags = TaggableManager(related_name="article_tags")
    article_image = models.ImageField(null=True, blank=True, upload_to="article_images/")

    def __str__(self) -> str:
        return self.title

    @property
    def length(self) -> int:
        return len(self.content)

    @property
    def get_category(self):
        return [v for v in self.categories.all()]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(ArticlePost, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("article_details", kwargs={
            "slug": self.slug
    })

UpdateView代码

class ArticlePostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = ArticlePost
    template_name = 'articles/article_form_update.html'
    form_class = ArticlePostForm

    def form_valid(self, form):
        form.instance.author = self.request.user
        messages.success(self.request, 'The article has been updated')
        return super().form_valid(form)

    def test_func(self):
        post = self.get_object()
        if self.request.user.id == post.article_users.user.id:
            return True
        return False

路由代码

urlpatterns = [
    path("posts/<slug>/", articles, name="articles"),
    path('<int:page_id>', pages.views.articles, name='page'),
    path("detail/<slug>/", detail, name="article_details"),
    path("new_article", new_article, name="new_article"),
    path("new_article/create_post", login_required(ArticlePostCreateView.as_view()), name="create_article"),
    path("post/<slug:slug>/update/", ArticlePostUpdateView.as_view(), name="update_post_article"),
    path('categories_list', categories_list, name="categories_list"),
    path("search_article_post", search_article_post, name="search_article_post"),
    path("category/<slug>/", category_articles, name="category_articles"),
    path("sort_by/<str:typesort>", articles_sort, name="articles_sort"),
]

表单代码

class ArticlePostForm(forms.ModelForm):
    class Meta:
        model = ArticlePost
        fields = ("title", "categories", "content", "article_tags", 'article_image')
        exclude = ["article_users"]

        widget = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.TextInput(attrs={'class': 'form-control'}),
            'categories': forms.Select(attrs={'class': 'form-control'}),
            'article_tags': forms.Select(attrs={'class': 'form-control'}),
            'article_image': forms.Select(attrs={'class': 'form-control'}),
        }
    
    def __setitem__(self, i, elem):
        self.list[i] = elem

表单模板代码

<div class="form-group">
    <form method="POST" action="{% url 'update_post_article' slug=post.slug %}">
        {% csrf_token %}
        <div class="centered_create_post">
            {% render_field form.title placeholder="Enter title" class+="form-control each_post_create" %}
            {% render_field form.content  placeholder="Enter content" class+="form-control each_post_create pst_create_categories " %}
            {% render_field form.categories  class+="form-control each_post_create pst_create_categories " %}
            {% render_field form.article_image  class+="form-control each_post_create" %}
            <div class="pull-left"><button type="submit" class="btn_create_post">Update Post</button></div>
        </div>
        <div class="clearfix"></div>
    </div>
    <div class="clearfix"></div>
</div>
</form>

问题修复方案

1. 修正UpdateView字段赋值错误

模型中关联作者的字段是article_users(关联Author模型),不是author,需修改form_valid方法:

def form_valid(self, form):
    # 假设当前用户对应唯一的Author实例,可根据实际关联逻辑调整
    form.instance.article_users = Author.objects.get(user=self.request.user)
    messages.success(self.request, '文章已更新')
    return super().form_valid(form)

2. 修复模板上下文与表单提交路径

  • UpdateView默认将当前对象放入上下文,变量名为object或模型小写形式articlepost;如果需要post变量,在视图中添加:
def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['post'] = self.get_object()
    return context
  • 表单可省略action属性,Django会自动处理提交路径;若保留则使用{{ post.slug }}(需确保post在上下文):
<form method="POST" action="{% url 'update_post_article' slug=post.slug %}">

3. 修复表单类错误

  • 修正widget拼写:Meta类中应为widgets(复数),否则样式不生效;
  • 删除多余方法:移除__setitem__方法,该方法会破坏表单内部结构导致组件无法渲染;
  • 匹配字段对应widget类型:
    • content是TextField,改用forms.Textarea;
    • categories是ManyToManyField,改用SelectMultiple或CheckboxSelectMultiple;
    • article_tags是TaggableManager,使用TagWidget(需导入from taggit.forms import TagWidget);
    • article_image是ImageField,改用ClearableFileInput;

修改后的表单类:

from taggit.forms import TagWidget

class ArticlePostForm(forms.ModelForm):
    class Meta:
        model = ArticlePost
        fields = ("title", "categories", "content", "article_tags", 'article_image')
        exclude = ["article_users"]

        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'class': 'form-control'}),
            'categories': forms.SelectMultiple(attrs={'class': 'form-control'}),
            'article_tags': TagWidget(attrs={'class': 'form-control'}),
            'article_image': forms.ClearableFileInput(attrs={'class': 'form-control'}),
        }

4. 修复模板渲染依赖

若使用{% render_field %},需在模板顶部加载crispy标签:

{% load crispy_forms_tags %}

内容的提问来源于stack exchange,提问作者Blade Runner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:05:54