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

Django学生成绩系统前端CSV导入失效排查请求

前端CSV导入失效但Django Admin导入正常的排查问题

我开发了一款学生评估用的Django应用,app_nilai模块包含absensi、tugas、uts、uas等成绩字段,通过外键关联app_matkul模块的mahasiswa、kelas、matakuliah对象。当前端页面上传CSV文件时导入功能完全失效,但Django Admin后台的导入功能可正常运行,且前端操作后无任何错误提示。以下是相关代码,请求排查问题所在。


Forms.py (app_nilai)

class NilaiForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(NilaiForm, self).__init__(*args, **kwargs)
        self.fields['mahasiswa'].widget.attrs['readonly'] = True
        self.fields['mahasiswa'].widget.attrs['class'] = 'form-control-plaintext'

    class Meta:
        model = Nilai
        fields = ('mahasiswa', 'absensi', 'tugas', 'uts', 'uas')
        widgets = {
            'mahasiswa': forms.TextInput(attrs={'readonly': 'readonly', 'class': 'form-control-plaintext'}),
            'absensi': forms.TextInput(attrs={'class': 'form-control'}),
            'tugas': forms.TextInput(attrs={'class': 'form-control'}),
            'uts': forms.TextInput(attrs={'class': 'form-control'}),
            'uas': forms.TextInput(attrs={'class': 'form-control'})
        }

class UploadCSVForm(forms.Form):
    csv_file = forms.FileField()

views.py (app_nilai)

def import_csv(request, kelas_id):
    kelas = get_object_or_404(Kelas, id=kelas_id)
    
    if request.method == 'POST':
        form = UploadCSVForm(request.POST, request.FILES)
        if form.is_valid():
            csv_file = request.FILES['csv_file']

            dataset = Dataset()
            imported_data = dataset.load(csv_file.read().decode('utf-8'), format='csv')

            nilai_resource = NilaiResource()
            result = nilai_resource.import_data(imported_data, dry_run=True, use_transactions=True, raise_errors=True, kelas_id=kelas_id)

            if not result.has_errors():
                import_result = nilai_resource.import_data(imported_data, dry_run=False, use_transactions=True, raise_errors=True, kelas_id=kelas_id, update=True)
                messages.success(request, 'Data berhasil diimpor.')
            else:
                messages.error(request, 'Terjadi kesalahan saat mengimpor data.')
        else:
            messages.error(request, 'Form tidak valid.')
        return redirect('nilai_kelas', kelas_id=kelas_id)

    form = UploadCSVForm()
    return render(request, 'import_csv.html', {'form': form, 'kelas': kelas})

resource.py (app_nilai)

class NilaiResource(resources.ModelResource):
    data_id = fields.Field(
        column_name='id',
        attribute='pk'
    )

    mahasiswa = fields.Field(
        column_name='mahasiswa',
        attribute='mahasiswa',
        widget=ForeignKeyWidget(Mahasiswa, 'id')
    )
    
    matakuliah = fields.Field(
        column_name='matakuliah',  # Ganti nama kolom ini untuk menghindari konflik
        attribute='mata_kuliah',
        widget=ForeignKeyWidget(MataKuliah, 'id')
    )

    kelas = fields.Field(
        column_name='kelas',
        attribute='kelas',
        widget=ForeignKeyWidget(Kelas, 'id')
    )

    class Meta:
        model = Nilai
        fields = ('data_id', 'mahasiswa', 'matakuliah', 'kelas', 'absensi', 'tugas', 'uts', 'uas')
        import_id_fields = ('data_id',)

    def before_import_row(self, row, **kwargs):
        kelas_id = kwargs.get('kelas_id')
        row['kelas'] = kelas_id

模型代码 (app_nilai)

from tkinter import CASCADE
from django.core.validators import MaxValueValidator
from django.db import models
from django.contrib.auth.models import User
from app_matkul.models import Kelas, Mahasiswa, MataKuliah

class Nilai(models.Model):
    mahasiswa = models.ForeignKey(Mahasiswa, on_delete=models.SET_NULL, blank=True, null=True)
    mata_kuliah = models.ForeignKey(MataKuliah, on_delete=models.SET_NULL,blank=True,null=True)
    kelas = models.ForeignKey(Kelas, on_delete=models.SET_NULL,blank=True,null=True)

    absensi = models.IntegerField(default=0, validators=[MaxValueValidator(100)])
    tugas = models.IntegerField(default=0, validators=[MaxValueValidator(100)])
    uts = models.IntegerField(default=0, validators=[MaxValueValidator(100)])
    uas = models.IntegerField(default=0, validators=[MaxValueValidator(100)])
    updated_at = models.DateTimeField(auto_now=True)
    
    @property
    def perhitungan_nilai(self):
        nilai_absen = self.absensi * (15/100)
        nilai_tugas = self.tugas * (35/100)
        nilai_uts = self.uts * (20/100)
        nilai_uas = self.uas * (30/100)
        olah = nilai_absen + nilai_tugas + nilai_uts + nilai_uas
        
        if olah >=60 and olah <=70 :
            return 70
        
        else :
            return int (olah)
    
    def logika_nilai(self):
        if self.perhitungan_nilai >=80:
            return 'A'
        
        elif self.perhitungan_nilai >=75:
            return 'AB'
        
        elif self.perhitungan_nilai >=70:
            return 'B'
        
        elif self.perhitungan_nilai >=50:
            return 'D'

        else :
            return 'E'
        
    @classmethod
    def rata_rata_nilai(cls, kelas_id):
        nilai_mahasiswa = cls.objects.filter(kelas__id=kelas_id)
        total_nilai = sum(a.perhitungan_nilai for a in nilai_mahasiswa)
        count = nilai_mahasiswa.count()
        return total_nilai / count if count > 0 else 0
        
    def __str__(self):
        return str(self.mahasiswa.nama)
    
    class Meta :
        ordering = ['mahasiswa']
        verbose_name_plural = '1. Nilai Akhir'

前端HTML代码

<form method="POST" enctype="multipart/form-data" action="{% url 'import_csv' kelas.id %}">
  {% csrf_token %}
  <div class="mb-3">
      <label for="csv_file" class="form-label">Import File CSV</label>
      <input type="file" class="form-control" id="csv_file" name="csv_file" accept=".csv" required>
  </div>
  <button type="submit" class="btn btn-sm btn-outline-primary">Import CSV</button>
  <a href="{% url 'export_csv' kelas.id %}" class="btn btn-sm btn-outline-info">Unduh Template CSV</a>
</form>

排查方向

  • CSV字段匹配问题:检查前端上传的CSV是否包含data_id字段,因为*import_id_fields = ('data_id',)*指定该字段为导入匹配依据。如果CSV缺少该字段,会导致无法匹配或创建记录,而Admin可能自动处理了主键生成逻辑。同时确认matakuliah、mahasiswa列是否对应关联模型的id值,避免非数值内容。
  • 参数传递有效性:在before_import_row中添加日志打印(如print(kelas_id)),确认kelas_id是否正确传递。若传递失败,row['kelas']会被设为None,导致导入记录未关联指定班级,看起来像是导入失效。
  • dry_run与实际导入的差异:暂时注释dry_run=True的校验步骤,直接执行实际导入,排查是否dry_run未检测到但实际导入存在的错误。同时确认update=True参数的逻辑:若CSV中data_id不存在,是否会自动创建新记录?
  • 消息提示渲染问题:检查前端页面是否正确渲染了Django的messages框架。如果成功/错误提示未显示,会误以为导入失效,但实际操作已执行。
  • CSV编码问题:若上传的CSV不是UTF-8编码,csv_file.read().decode('utf-8')会出现解码错误但未抛出异常,导致导入中断。可以添加try-except捕获UnicodeDecodeError并给出提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 15:30:55