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

Django案件卡片保存/编辑功能失效,请求故障排查

问题:修改BusinessCard模型后,案件卡片创建与编辑无法保存数据

终端输出日志

[03/Oct/2023 16:15:52] "GET /create/?csrfmiddlewaretoken=xgcCZx4x2RjaTeFT5Sn6OBqC3k9VZUBO69tG4zJMiNuVwne9NTX1LXpdRJqn03AZ&original_name=222&author=1&case_category=3&defendant=Петров&article=200&sides_case=3&preliminary_hearing=20.09.2023 HTTP/1.1" 200 8459

相关代码

Model

class BusinessCard(models.Model):
    '''7. Модель карточки по делу'''
    original_name = models.CharField(
        unique=True,
        max_length=100,
        verbose_name='номер дела'
        )
    author = models.ForeignKey(
        User,
        models.SET_NULL,
        blank=True,
        null=True,
        related_name='cards',
        verbose_name='Автор карточки'
        )
    case_category = models.ForeignKey(
        Category,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='cards',
        verbose_name='Категория дела'
    )
    defendant = models.CharField(
        max_length=150,
        verbose_name='подсудимый'
    )
    under_arrest = models.BooleanField(
        verbose_name='под стражей'
        )
    article = models.PositiveSmallIntegerField(
        verbose_name='Статья УК РФ'
    )
    pub_date = models.DateTimeField(
        auto_now_add=True,
        verbose_name='Дата создания/изменения карточки'
        )
    sides_case = models.ManyToManyField(
        SidesCase,
        verbose_name='Поля сторон по делу'
    )
    preliminary_hearing = models.DateField(
        verbose_name='Дата предварительного слушания/(с/з)'
    )

    class Meta:
        ordering = ('pub_date',)
        verbose_name = 'Карточка на дело'
        verbose_name_plural = 'карточка на дело'

    def __str__(self):
        return self.original_name

Views

@login_required
def card_create(request):
    '''Шаблон создание карточки'''
    template = 'create_card.html'
    form = CardForm(request.POST or None)
    if form.is_valid():
        card = form.save(commit=False)
        card.author = request.user
        card.save()
        form = CardForm()
        return redirect('business_card:profile', request.user)
    return render(request, template, {'form': form})


@login_required
def card_edit(request, post_id):
    '''Шаблон редактирования карточки'''
    card = get_object_or_404(
        BusinessCard.objects.select_related(
            'case_category', 'author'), id=post_id
    )
    if request.user != card.author:
        return redirect('business_card:business_card_detail', card.pk)
    form = CardForm(request.POST or None, instance=card)
    if form.is_valid():
        form.save()
        return redirect('business_card:business_card_detail', card.pk)
    form = CardForm(instance=card)
    context = {
        'form': form,
        'is_edit': True,
        'card': card,
    }
    return render(request, 'create_card.html', context)

Forms

class CardForm(ModelForm):
    class Meta:
        model = BusinessCard
        fields = [
            'original_name', 'author', 'case_category',
            'defendant', 'under_arrest', 'article', 'sides_case',
            'preliminary_hearing'
        ]

        labels = {
            'original_name': 'Номер дела',
            'case_category': 'категория'
        }

        help_texts = {
            'original_name': 'Номер нового дела',
            'case_category': 'Категория'
        }

模板代码

{% extends 'base.html' %}
{% block Title %}<title>{% if is_edit %} Редактировать карточку {% else%} Новая карточка {% endif %}</title>{% endblock %}
{% block content %}
  <div class="container py-5">
    <div class="row justify-content-center">
      <div class="col-md-8 p-5">
        <div class="card">
          <div class="card-header">
            {% if is_edit %} Редактировать карточку {% else%} Новая карточка {% endif %}
          </div>
          <div class="card-body">
            {% if form.errors %}
              {% for field in form %}
                {% for error in field.errors %}
                  <div class="alert alert-danger">
                    {{ error|escape }}
                  </div>
                {% endfor %}
              {% endfor %}
              {% for error in form.non_field_errors %}
                <div class="alert alert-danger">
                  {{ error|escape }}
                </div>
              {% endfor %}
          {% endif %}
          <form method="card"
            {% if card %}
              "{% url 'business_card:card_edit' card.pk %}"
            {% else %}
              "{% url 'business_card:card_create' %}"
            {% endif %}>
            {% csrf_token %}
            {% for field in form %}
              <div class="form-group row my-3 p-3 textarea">
                <label for="{{field.id_for_label}}">
                  {{ field.label }}
                  {% if field.label.required %}
                    <span class="required text-danger" >*</span>
                  {% endif %}
                </label>
                  {{ field }}
                  {% if field.help_text %}
                  <p class="help">{{ field.help_text|safe }}</p>
                  {% endif %}
              </div>
            {% endfor %}
            <div class="form-group row my-3 p-3">
              <label for="{{ field.id_for_label }}">
                {{ field.label }}
              </label>
            </div>
            <div class="d-flex justify-content-end">
              <button type="submit" class="btn btn-primary">
                {% if is_edit %}
                  Сохранить
                {% else %}
                  Добавить
                {% endif %}
              </button>
            </div>
          </form>
          </div>
        </div>
      </div>
    </div>
  </div>
{% endblock %}

问题排查与修复

1. 表单提交方法错误(核心问题)

模板中表单的method属性被错误设置为"card",导致表单以GET方式提交,数据通过URL参数传递而非POST请求。视图中request.POST为空,form.is_valid()无法通过,数据无法保存。

修复模板中的form标签:

<form method="post" action="{% if card %}{% url 'business_card:card_edit' card.pk %}{% else %}{% url 'business_card:card_create' %}{% endif %}">
  • 将method="card"改为method="post"
  • 修正action属性写法,移除多余引号,确保URL正确渲染

2. 多对多字段未保存

创建视图中使用commit=False保存模型实例后,多对多字段(sides_case)不会自动保存,必须调用form.save_m2m()完成关联数据存储。

修改card_create视图:

@login_required
def card_create(request):
    '''Шаблон создание карточки'''
    template = 'create_card.html'
    form = CardForm(request.POST or None)
    if form.is_valid():
        card = form.save(commit=False)
        card.author = request.user
        card.save()
        form.save_m2m()  # 新增该行保存多对多关系
        return redirect('business_card:profile', request.user)
    return render(request, template, {'form': form})
  • 移除不必要的form = CardForm(),避免清空表单状态
  • 添加form.save_m2m()保存多对多字段

3. 表单包含不必要的author字段

表单中包含author字段,但创建逻辑中手动设置当前登录用户为作者,前端无需显示该字段,否则可能导致提交冲突。

修改CardForm:

class CardForm(ModelForm):
    class Meta:
        model = BusinessCard
        fields = [
            'original_name', 'case_category',  # 移除author字段
            'defendant', 'under_arrest', 'article', 'sides_case',
            'preliminary_hearing'
        ]

        labels = {
            'original_name': 'Номер дела',
            'case_category': 'категория'
        }

        help_texts = {
            'original_name': 'Номер нового дела',
            'case_category': 'Категория'
        }

4. 编辑视图错误重置表单

编辑视图中,当form.is_valid()不通过时重新实例化表单,导致表单错误信息丢失,用户无法看到验证失败原因。

修改card_edit视图:

@login_required
def card_edit(request, post_id):
    '''Шаблон редактирования карточки'''
    card = get_object_or_404(
        BusinessCard.objects.select_related(
            'case_category', 'author'), id=post_id
    )
    if request.user != card.author:
        return redirect('business_card:business_card_detail', card.pk)
    form = CardForm(request.POST or None, instance=card)
    if form.is_valid():
        form.save()
        return redirect('business_card:business_card_detail', card.pk)
    # 移除form = CardForm(instance=card),保留带错误信息的form
    context = {
        'form': form,
        'is_edit': True,
        'card': card,
    }
    return render(request, 'create_card.html', context)

5. 模板中多余的字段标签

模板末尾有一段多余的字段标签代码,会导致变量错误(field在循环外未定义),需删除:

<div class="form-group row my-3 p-3">
  <label for="{{ field.id_for_label }}">
    {{ field.label }}
  </label>
</div>

验证修复效果

完成上述修改后:

  1. 表单将以POST方式提交数据,视图能正确获取表单内容
  2. 多对多关系会被正常保存
  3. 表单不再显示不必要的author字段,避免冲突
  4. 验证失败时会显示错误信息,方便用户修正
  5. 多余代码被移除,避免模板错误

内容的提问来源于stack exchange,提问作者Андрей

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:27:33