首頁  >  文章  >  後端開發  >  如何將 CSV 檔案上傳到 DJANGO REST

如何將 CSV 檔案上傳到 DJANGO REST

DDD
DDD原創
2024-11-05 19:25:02731瀏覽

將 CSV 檔案上傳到 Django REST(尤其是在原子設定中)是一項簡單的任務,但讓我感到困惑,直到我發現了一些我將與您分享的技巧。
在本文中,我將使用郵遞員(代替前端),並將分享您需要在郵遞員上設定什麼才能透過圖片發送請求。

我們想要的

  1. 透過 Django Rest 將 CSV 上傳到資料庫
  2. 使操作原子化,即csv 中任何行中的任何錯誤都應導致整個操作的完全回滾,因此我們可以避免剪切csv 文件的壓力,即識別使其成功的行部分的麻煩數據庫和那些因為中途錯誤而沒有的資料庫! (部分條目)。所以我們想要一個不是全有或全無的事情!!

方法

  1. 假設您已經安裝了 Django 和 Django REST,第一步是安裝 pandas,一個用於資料操作的 Python 函式庫。

pip 安裝 pandas

  1. 郵差中的下一步:在正文標籤中,選擇表單資料並新增一個鍵(任何任意名稱)。在同一儲存格中,將滑鼠懸停在單元格的最右側,然後使用下拉式選單將選項從文字變更為檔案。當您執行此操作時,Postman 會自動將 headers 中的 Content-Type 設定為 multipart/form-data。

對於值單元格,按一下「選擇檔案」按鈕並上傳 CSV。請看下面的截圖

HOW TO UPLOAD A CSV FILE TO DJANGO REST

在 headers 下,設定 Content-Disposition 並將值設為 form-data;名稱=「檔案」;檔案名稱=「你的檔案名稱.csv」。將 your_file_name.csv 替換為您的實際檔案名稱。檢查下面的螢幕截圖。

HOW TO UPLOAD A CSV FILE TO DJANGO REST

  1. 在Django視圖中,程式碼如下:
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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn