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

求助:Django表单提交的数据无法保存至MySQL数据表

Django表单数据无法保存到MySQL数据库问题解析

问题描述

我正尝试将通过Django表单收集的数据保存到MySQL数据库中。页面逻辑是先让用户输入信息生成员工列表,再保存对应列表项的数据。虽然POST请求里能看到数据,但始终无法存入数据库。推测问题出在保存逻辑,但找不到原因,Django日志和数据库错误日志都没报错。

相关代码

Model代码

class MonthlySheet(models.Model):
    month = models.IntegerField()
    year = models.IntegerField()
    org_name = models.ForeignKey(Establishment, on_delete=models.DO_NOTHING)
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE, null=True, default=None)
    wages = models.IntegerField()
    gross = models.IntegerField()
    total_work_days = models.IntegerField()
    present_days = models.IntegerField()
    calc_twelve = models.DecimalField(max_digits=10, decimal_places=2)
    calc_eight_three_three = models.DecimalField(max_digits=10, decimal_places=2)
    calc_diff = models.DecimalField(max_digits=10, decimal_places=2)
    calc_point_seven_five = models.DecimalField(max_digits=10, decimal_places=2)

    def get_absolute_url(self):
        return reverse('monthly_sheet_detail', kwargs={'pk': self.pk})

    def save(self, *args, **kwargs):
        self.pk = f"{self.month}.{self.year}"
        super().save(*args, **kwargs)

View代码

class AddMonthlySheetView(FormView):
    template_name = 'add_monthlysheet.html'
    form_class = CustomMonthlySheetForm
    model = MonthlySheet

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        last_month, year, total_work_days = set_previous_month()
        context['last_month'] = last_month
        context['year'] = year
        context['total_work_days'] = total_work_days
        context['establishments'] = Establishment.objects.all()
        establishment_id = self.request.POST.get('org_name')  # Use POST instead of GET
        if establishment_id:
            employees = get_employees_from_establishment(establishment_id)
            context['employees'] = employees
        return context

    def form_valid(self, form):
        month = form.cleaned_data['month']
        year = form.cleaned_data['year']
        org_name = form.cleaned_data['org_name']

        employees = form.cleaned_data['employee']
        wages = form.cleaned_data['wages']
        gross = form.cleaned_data['gross']
        total_work_days = form.cleaned_data['total_work_days']
        present_days = form.cleaned_data['present_days']

        for employee in employees:
            MonthlySheet.objects.create(
                month=month,
                year=year,
                org_name=org_name,
                employee=employee,
                wages=wages,
                gross=gross,
                total_work_days=total_work_days,
                present_days=present_days
            )

        return redirect('employee_list')

def monthly_sheet_detail(request, pk):
    monthly_sheet = get_object_or_404(MonthlySheet, pk=pk)
    return render(request, 'monthly_sheet_detail.html', {'monthly_sheet': monthly_sheet})

Form代码

class CustomMonthlySheetForm(forms.ModelForm):
    month = forms.IntegerField()
    year = forms.IntegerField()
    org_name = forms.ModelChoiceField(queryset=Establishment.objects.all(), required=True)
    employee = forms.ModelMultipleChoiceField(queryset=Employee.objects.filter(isactive=True), required=True, widget=forms.CheckboxSelectMultiple)
    wages = forms.IntegerField()
    gross = forms.IntegerField()
    total_work_days = forms.IntegerField()
    present_days = forms.IntegerField()

    class Meta:
        model = MonthlySheet
        fields = ('month', 'year', 'org_name', 'employee', 'wages', 'gross', 'total_work_days', 'present_days')

HTML模板代码

{% extends 'base.html' %}

{% block title %}Add Monthly Sheet{% endblock %}

{% block content %}

<div class="content-wrapper">
  <div class="container">
    <h1>Monthly Sheet</h1>
    <br>
    <div class="wide-seperator"></div>
      <form method="POST" id="select-unit">
          {% csrf_token %}
          <div class="form-field">
            <label for="month">For the Month of:</label>
            <input type="number" id="month" name="month" value="{{ last_month }}" required readonly>
            <label for="year">in Year:</label>
            <input type="number" id="year" name="year" value="{{ year }}" required readonly>
          </div>
            <br>
            <div class="form-field">
              <label for="org_name">Establishment:</label>
              <select name="org_name" id="org_name" required>
                <option value="">---Select Establishment---</option>
                {% for establishment in establishments %}
                  <option value="{{ establishment.id }}"> {{ establishment.org_name }}</option>
                {% endfor %}
              </select>
              <input type="submit" value="Show">
            </div>
        </form>
      </div>
    </div>
  </div>

<div class="monthlysheet-list-container">  
  <form method="POST">
    {% csrf_token %}
    <input type="hidden" name="month" value="{{ last_month }}">
    <input type="hidden" name="year" value="{{ year }}">
    {% if employees %}
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>UAN</th>
            <th>Wages</th>
            <th>Gross</th>
            <th>Total Days</th>
            <th>Present Days</th>
          </tr>
        </thead>
        <tbody>
          {% for employee in employees %}
          <tr>
            <td>{{ employee.name }}</td>
            <td>{{ employee.uan }}</td>
            <input type="hidden" name="employee" value="{{ employee.name }}">
            <input type="hidden" name="org_name" value="{{ employee.org_name.id }}">
            <td><input type="number" name="wages" value="{{ employee.wages }}" required></td>
            <td><input type="number" name="gross" value="{{ employee.gross }}" required></td>
            <td><input type="number" name="total_work_days" value="{{ total_work_days }}" required></td>
            <td><input type="number" name="present_days" value="{{ present_days }}" required></td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    {% endif %}
    <input type="submit" value="Save Data">
  </form>
</div>    

{% endblock %}

URL配置代码

urlpatterns = [
    path('add_monthlysheet/', AddMonthlySheetView.as_view(), name='add_monthlysheet'),
    path('monthlysheet/<int:pk>/', views.monthly_sheet_detail, name='monthly_sheet_detail'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

浏览器控制台截图

浏览器控制台截图

问题排查与解决方案

核心问题点

  1. 主键类型不匹配
    Model中重写save方法,强制将主键设置为"{month}.{year}"格式的字符串,但MySQL默认主键是整数类型,类型冲突导致数据无法写入,且Django内部捕获异常未抛出,所以无日志报错。

  2. 表单字段值传递错误
    HTML中employee隐藏字段传递的是员工姓名,而ModelMultipleChoiceField需要接收员工ID,导致form.cleaned_data['employee']无法解析出有效员工对象。

  3. 必填计算字段未赋值
    Model中calc_twelve等字段无默认值,创建对象时未赋值,触发数据库非空约束,事务回滚后无日志记录。

修复方案

1. 修正主键逻辑

删除自定义save方法中设置主键的代码,使用Django默认自增主键;若需按月份+年份+员工唯一标识,添加联合唯一约束:

class MonthlySheet(models.Model):
    # ... 原有字段 ...

    def get_absolute_url(self):
        return reverse('monthly_sheet_detail', kwargs={'pk': self.pk})

    # 移除自定义的save方法中设置pk的代码

    class Meta:
        unique_together = ('month', 'year', 'employee')

2. 修正表单员工字段传递值

将HTML中employee隐藏字段改为传递ID,并添加[]支持多选:

<input type="hidden" name="employee[]" value="{{ employee.id }}">

3. 补充计算字段赋值

在form_valid中根据业务逻辑为计算字段赋值:

def form_valid(self, form):
    # ... 原有代码 ...
    for employee in employees:
        # 示例计算逻辑,根据实际业务调整
        calc_twelve = wages * 0.12
        calc_eight_three_three = gross * 0.0833
        calc_diff = calc_twelve - calc_eight_three_three
        calc_point_seven_five = wages * 0.75

        MonthlySheet.objects.create(
            # ... 原有字段 ...
            calc_twelve=calc_twelve,
            calc_eight_three_three=calc_eight_three_three,
            calc_diff=calc_diff,
            calc_point_seven_five=calc_point_seven_five
        )
    # ... 原有代码 ...

4. 调试建议

  • 在form_valid中添加日志打印,确认清洗后的数据是否正确:
    import logging
    logger = logging.getLogger(__name__)
    
    def form_valid(self, form):
        logger.debug(f"清洗后的数据: {form.cleaned_data}")
        # ... 后续代码 ...
    
  • 在Django Shell中手动测试创建对象,排查具体异常:
    python manage.py shell
    from yourapp.models import MonthlySheet, Establishment, Employee
    org = Establishment.objects.first()
    emp = Employee.objects.first()
    MonthlySheet.objects.create(month=10, year=2024, org_name=org, employee=emp, wages=5000, gross=6000, total_work_days=22, present_days=20, calc_twelve=600, calc_eight_three_three=499.8, calc_diff=100.2, calc_point_seven_five=3750)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:26:58