python - 使用表单上传csv文件django

标签 python django csv export-to-csv

我正在处理一个学校管理项目,想要上传一个 CSV 文件并通过覆盖当前数据或在数据库中更新它来保存它。但它没有被添加到数据库中。另外,我喜欢添加更多字段,所以如果可能的话,使用动态(即通过循环),所以我以后不必更改它。 models.py

class Student(models.Model):
  registration_number = models.CharField(max_length=200, unique=True)
  firstname = models.CharField(max_length=200)
  surname = models.CharField(max_length=200)
  date_of_birth = models.DateField(default=timezone.now)
  current_class = models.ForeignKey(StudentClass, on_delete=models.SET_NULL, blank=True, null=True)
  date_of_admission = models.DateField(default=timezone.now)
  parent_mobile_number = models.CharField(max_length=15)
  address = models.TextField()

class StudentBulkUpload(models.Model):
  date_uploaded = models.DateTimeField(auto_now=True)
  csv_file = models.FileField(upload_to='students/bulkupload/')
forms.py
class StudentBulkUploadForm(forms.ModelForm):
  class Meta:
    model = StudentBulkUpload
    fields = ("csv_file",)

views.py
def uploadcsv(request):
  if request.method == 'GET':
    form = StudentBulkUploadForm()
    return render(request, 'students/students_upload.html', {'form':form})

  # If not GET method then proceed
  try:
    form = StudentBulkUploadForm(data=request.POST, files=request.FILES)
    if form.is_valid():
      csv_file = form.cleaned_data['csv_file']
    if not csv_file.name.endswith('.csv'):
      messages.error(request, 'File is not CSV type')
      return redirect('students:student-upload')
    # If file is too large
    if csv_file.multiple_chunks():
      messages.error(request, 'Uploaded file is too big (%.2f MB)' %(csv_file.size(1000*1000),))
      return redirect('students:student-upload')
    
    file_data = csv_file.read().decode('utf-8')
    lines = file_data.split('\n')

    # loop over the lines and save them in db. If error, store as string and then display
    for line in lines:
      fields = line.split(',')
      data_dict = {}
      print(data_dict)
      try:
        form = StudentBulkUploadForm(data_dict)
        if form.is_valid():
          form.save()
        else:
          logging.getLogger('error_logger').error(form.errors.as_json())
      except Exception as e:
        logging.getLogger('error_logger').error(form.errors.as_json())
        pass
  except Exception as e:
    logging.getLogger('error_logger').error('Unable to upload file. ' + repr(e))
    messages.error(request, 'Unable to upload file. ' + repr(e))
  return redirect('students:student-upload')
student_upload.html
<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}

    <input type="submit" class="btn btn-success" value="Submit">
</form>

最佳答案

是否有必要通过表单传递数据并将其保存到db。否则,您可以简单地创建模型的对象并将字典传递给它并保存。
我认为你应该(简而言之):

  • 首先使用 StudentBulkUpload() 上传并保存文件
  • 获取文件路径并读取内容
  • 如果模型字段和 csv 列具有相同的名称会更好
  • 循环遍历每一行并创建一个字典,其中仅包含一个迭代中的学生详细信息
  • 创建一个 Student() 的实例并将字典传递给它并保存
  • 对于外键,从 StudentClass() 获取对象使用 get()相应地与存储在 csv 中的值

  • 您可以通过两种方式保存学生详细信息,我认为:
  • 创建一个模型对象并通过正常方式读取每一行来赋值

  • new_student = Student()
    new_student.registration_number = fields[0]
    new_student.firstname = fields[1]
    # like so for other fields
    
    new_student.save()
    
  • 创建一个模型对象,创建一个键值字典,其中键对应于模型的字段名称。

  • # create a dictionary `new_student_details` containing values of a student
    
    new_student = Student()
    new_student.__dict__.update(new_student_details)
    new_student.save()
    

    创建一个函数来读取 csv 文件并保存学生详细信息
    import csv
    def save_new_students_from_csv(file_path):
        # do try catch accordingly
        # open csv file, read lines
        with open(file_path, 'r') as fp:
            students = csv.reader(fp, delimiter=',')
            row = 0
            for student in students:
                if row==0:
                    headers = student
                    row = row + 1
                else:
                    # create a dictionary of student details
                    new_student_details = {}
                    for i in range(len(headers)):
                        new_student_details[headers[i]] = student[i]
    
                    # for the foreign key field current_class in Student you should get the object first and reassign the value to the key
                    new_student_details['current_class'] = StudentClass.objects.get() # get the record according to value which is stored in db and csv file
    
                    # create an instance of Student model
                    new_student = Student()
                    new_student.__dict__.update(new_student_details)
                    new_student.save()
                    row = row + 1
            fp.close()
    

    您的代码应该如下所示:
    def uploadcsv(request):
        if request.method == 'GET':
            form = StudentBulkUploadForm()
            return render(request, 'students/students_upload.html', {'form':form})
    
        # If not GET method then proceed
        try:
            form = StudentBulkUploadForm(data=request.POST, files=request.FILES)
            if form.is_valid():
                csv_file = form.cleaned_data['csv_file']
                if not csv_file.name.endswith('.csv'):
                    messages.error(request, 'File is not CSV type')
                    return redirect('students:student-upload')
                # If file is too large
                if csv_file.multiple_chunks():
                    messages.error(request, 'Uploaded file is too big (%.2f MB)' %(csv_file.size(1000*1000),))
                    return redirect('students:student-upload')
    
                # save and upload file 
                form.save()
    
                # get the path of the file saved in the server
                file_path = os.path.join(BASE_DIR, form.csv_file.url)
    
                # a function to read the file contents and save the student details
                save_new_students_from_csv(file_path)
                # do try catch if necessary
                    
        except Exception as e:
            logging.getLogger('error_logger').error('Unable to upload file. ' + repr(e))
            messages.error(request, 'Unable to upload file. ' + repr(e))
        return redirect('students:student-upload')
    
    注意: csv 文件需要遵循正确的格式。您可以保存 Student()反正你喜欢。无论如何,文件需要上传和阅读。逐行Student()必须得救。这只是一个结构。随意进行必要的更改,因为我已经删除了您的大部分代码

    关于python - 使用表单上传csv文件django,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62912039/

    相关文章:

    MySQL加载忽略一些记录

    python - 为什么 "1 in (True, None)"在 python 中计算结果为 True?

    python - 如何使用 XLSXWRITER 的 set_y2_axis 函数设置最大边界?

    python - 在 python 中具有事件 TCP 连接的 HTTP 服务器

    django - apache服务器无法在Django项目中找到静态文件

    javascript - 如何仅在 Angular js 中从 tsv 加载数据后才呈现指令

    python - 如何在 Django ORM 中执行 GROUP BY ... COUNT 或 SUM?

    Python无法导入ssl模块

    django - 在 Django ORM 的子查询中返回多个值

    使用readr从cognos 8文件(utf 16)读入R数据帧