将 CSV 文件上传到 Django REST(尤其是在原子设置中)是一项简单的任务,但让我感到困惑,直到我发现了一些我将与您分享的技巧。
在本文中,我将使用邮递员(代替前端),并将分享您需要在邮递员上设置什么才能通过图片发送请求。
我们想要的
方法
pip 安装 pandas
对于值单元格,单击“选择文件”按钮并上传 CSV。请看下面的截图
在 headers 下,设置 Content-Disposition 并将值设置为 form-data;名称=“文件”;文件名=“你的文件名.csv”。将 your_file_name.csv 替换为您的实际文件名。检查下面的屏幕截图。
from rest_framework import status from rest_framework.views import APIView from rest_framework.parsers import FileUploadParser from rest_framework.response import Response from .models import BiodataModel from django.db import transaction import pandas as pd class UploadCSVFile(APIView): parser_classes = [FileUploadParser] def post(self,request): csv_file = request.FILES.get('file') if not csv_file: return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) # Validate file type if not csv_file.name.endswith('.csv'): return Response({"error": "File is not CSV type"}, status=status.HTTP_400_BAD_REQUEST) df = pd.read_csv(csv_file, delimiter=',',skiprows=3,dtype=str).iloc[:-1] df = df.where(pd.notnull(df), None) bulk_data=[] for index, row in df.iterrows(): try: row_instance= BiodataModel( name=row.get('name'), age=row.get('age'), address =row.get('address')) row_instance.full_clean() bulk_data.append(row_instance) except Exception as e: return Response({"error": f'Error at row {index + 2} -> {e}'}, status=status.HTTP_400_BAD_REQUEST) try: with transaction.atomic(): BiodataModel.objects.bulk_create(bulk_data) except Exception as e: return Response({"error": f'Bulk create error--{e}'}, status=status.HTTP_400_BAD_REQUEST) return Response({"msg":"CSV file processed successfully"}, status=status.HTTP_201_CREATED)
解释上面的代码:
该代码首先导入必要的包,定义基于类的视图并设置解析器类(FileUploadParser)。类中 post 方法的第一部分尝试从 request.FILES 获取文件并检查其可用性。
然后进行次要验证,通过检查扩展名来检查它是否是 CSV。
下一部分将其加载到 pandas 数据框中(非常像电子表格):
df = pd.read_csv(csv_file, delimiter=',',skiprows=3,dtype=str).iloc[:-1]
我将解释一些传递给加载函数的参数:
跳船
在读取加载的 csv 文件时,应该注意的是,本例中的 csv 是通过网络传递的,因此一些元数据(例如内容)会添加到文件的开头和结尾。这些东西可能很烦人,并且不是逗号分隔值 (csv) 形式,因此实际上可能会引发解析错误。这解释了为什么我使用skiprows=3来跳过包含元数据和标题的前3行并直接落在csv的正文上。如果删除跳过行或使用较少的数字,也许您可能会收到如下错误:错误标记数据。 C 错误,或者您可能会注意到从标头开始的数据。
dtype=str
Pandas 喜欢通过尝试猜测某些列的数据类型来证明自己很聪明。我希望所有值都是字符串,所以我使用 dtype=str
分隔符
指定单元格的分离方式。默认值通常是逗号。
iloc[:-1]
我必须使用 iloc 对数据帧进行切片,删除 df 末尾的元数据。
然后,下一行 df = df.where(pd.notnull(df), None) 将所有 NaNvalues 转换为 None。 NaNi 是 pandas 用来表示 None 的替代值。
下一个区块有点棘手。我们循环数据帧中的每一行,使用 BiodataModel 实例化行数据,使用 full_clean() 方法执行模型级验证(不是序列化器级),因为批量创建会绕过 Django 验证,然后将我们的创建操作添加到名为的列表中批量数据。是啊,添加还没运行!请记住,我们正在尝试执行原子操作(在批处理级别),因此我们想要全部或无。单独保存行不会给我们带来全部或没有行为。
然后是最后一个重要部分。在 transaction.atomic() 块(提供所有或不提供行为)中,我们运行 BiodataModel.objects.bulk_create(bulk_data) 来一次保存所有行。
还有一件事。注意 for 循环中的索引变量和 except 块。在 except 块错误消息中,我将 2 添加到从 df.iterrows() 派生的索引变量中,因为在 Excel 文件中查看时,该值与它所在的行不完全匹配。 except 块会捕获任何错误,并在 Excel 中打开时构造一条具有确切行号的错误消息,以便上传者可以轻松找到 Excel 文件中的行!
感谢您的阅读!!!
使用的工具版本
from rest_framework import status from rest_framework.views import APIView from rest_framework.parsers import FileUploadParser from rest_framework.response import Response from .models import BiodataModel from django.db import transaction import pandas as pd class UploadCSVFile(APIView): parser_classes = [FileUploadParser] def post(self,request): csv_file = request.FILES.get('file') if not csv_file: return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) # Validate file type if not csv_file.name.endswith('.csv'): return Response({"error": "File is not CSV type"}, status=status.HTTP_400_BAD_REQUEST) df = pd.read_csv(csv_file, delimiter=',',skiprows=3,dtype=str).iloc[:-1] df = df.where(pd.notnull(df), None) bulk_data=[] for index, row in df.iterrows(): try: row_instance= BiodataModel( name=row.get('name'), age=row.get('age'), address =row.get('address')) row_instance.full_clean() bulk_data.append(row_instance) except Exception as e: return Response({"error": f'Error at row {index + 2} -> {e}'}, status=status.HTTP_400_BAD_REQUEST) try: with transaction.atomic(): BiodataModel.objects.bulk_create(bulk_data) except Exception as e: return Response({"error": f'Bulk create error--{e}'}, status=status.HTTP_400_BAD_REQUEST) return Response({"msg":"CSV file processed successfully"}, status=status.HTTP_201_CREATED)
以上是如何将 CSV 文件上传到 DJANGO REST的详细内容。更多信息请关注PHP中文网其他相关文章!