【问题标题】:find the differences between two csv files and mark em找出两个 csv 文件之间的差异并标记 em
【发布时间】:2018-07-13 18:24:28
【问题描述】:

我正在使用 Django 制作一个网站,该网站允许用户上传 2 个 csv 文件,然后网站会找到这两个文件之间的差异,打印差异并添加一个新的“更改”列。在每个记录的新列中,每一行都会获得一个新的“更改”或“添加”或“删除”新记录。假设没有重复。这是目前为止的views.py代码。

from django.shortcuts import render
from django.http import HttpResponse
import difflib
import datetime
import csv
from django.http import HttpResponseRedirect
from django.http import FileResponse
from .forms import FileForm
from .forms import UploadFileForm

def handle_uploaded_file(filename_1, filename_2):
    """ handle_uploaded_file is a function that takes 2 files uploaded by the users """

    with open(filename_1, newline='') as f_old:
        csv_old = csv.reader(f_old, delimiter='\t')
        header = next(csv_old)
        old_data = {row[0] : row for row in csv_old}

    with open(filename_2, newline='') as f_new:
        csv_new = csv.reader(f_new, delimiter='\t')
        header = next(csv_new)
        new_data = {row[0] : row for row in csv_new}

    set_new_data = set(new_data)
    set_old_data = set(old_data)

    added = [['Added'] + new_data[v] for v in set_new_data - set_old_data]
    deleted = [['Deleted'] + old_data[v] for v in set_old_data - set_new_data]
    in_both = set_old_data & set_new_data
    changed = [['Changed'] + new_data[v] for v in in_both if old_data[v] != new_data[v]]

    with open('difference.csv', 'w', newline='') as f_output:
        csv_output = csv.writer(f_output, delimiter='\t')
        csv_output.writerow(['History'] + header)
        csv_output.writerows(sorted(added + deleted + changed, key=lambda x: x[1:]))

def index(request): # index is a function for the upload button
    if request.method == 'POST': # POST method inserts something to the server
        print(request.FILES)
        form = UploadFileForm(request.POST, request.FILES)
        print(form.errors)
        if form.is_valid():
            print("cool")
            handle_uploaded_file(request.FILES.get('file1'),request.FILES.get('file2'))
            return HttpResponseRedirect('results/')
    else:
        form = UploadFileForm()
    return render(request, 'hello.html', {'form': form})

def results(request): # results is a function that sends difference.csv back to the user once the file is ready
    file_path = (r'C:\Users\Public\Documents\PycharmProjects\filecomparison\difference.csv') #  adding an absolute path in the server, pinpoints that exact file, very important, r is to produce raw string and handle unicodeescape error
    response = FileResponse(open(file_path, 'rb'))
    response['Content-Type'] = 'text/csv' # the type of the file that will be send is .txt/.csv
    response['Content-Disposition'] = 'attachment; filename=difference.csv' # produces an attachment file for users to download called with difference in .csv file
    return response

这是旧的.csv

Name    Emp_ID  Zone_ID Zone Name   Customer Type   First Name  Cust_ID Balance Loan    Asset Name  Serial  Purchase_ID 
Jack    4145    10-34-2Z-71ABD      Bakery  Matt    41235   -123.567    123.44  43521_BLACK_BURNER  52+007XX    QOLO-LW09   
Bob 4146    10-35-2Z-71ABD      Woodsmith   Dylan   12315   -129.12 194.44  43521_BLACK_BURNER  50+001XX    KDFL-LW10   
Rick    4147    10-34-2Z-73ABD      Gunrange    Robin   64234   -134.12 133.44  43521_BLACK_BURNER  32+003XX    HFDO-LW11   
Shane   4148    10-34-2Z-72ABD      Restaurant  Aldo    31356   -121.23 949.44  43521_BLACK_BURNER  89+004XX    BDSM-LW12   

这是新的.csv

Name    Emp_ID  Zone_ID Zone Name   Customer Type   First Name  Cust_ID Balance Loan    Asset Name  Serial  Purchase_ID
Jack    4145    10-34-2Z-71ABD      Bakery  Matt    41235   -123.567    123.44  43521_BLACK_BURNER  52+007XX    QOLO-LW09
Bob 4146    10-35-2Z-71ABD      Woodsmith   Ron 12315   -129.12 194.44  43521_BLACK_BURNER  50+001XX    KDFL-LW10
Jane    1234    19-35-2K-72XYZ      EO  Karen   50980   -547.95 544.39  43521_BLACK_BURNER  50+0076KK   ERQW-BN66
Shane   4148    10-34-2Z-72ABD      Restaurant  Aldo    31356   -121.23 949.44  43521_BLACK_BURNER  89+004XX    BDSM-LW12

这应该是差异.csv

Name    Emp_ID  Zone_ID Zone Name   Customer Type   First Name  Cust_ID Balance Loan    Asset Name  Serial  Purchase_ID Changes
Bob 4146    10-35-2Z-71ABD      Woodsmith   Ron 12315   -129.12 194.44  43521_BLACK_BURNER  50+001XX    KDFL-LW10   Changed
Jane    1234    19-35-2K-72XYZ      EO  Karen   50980   -547.95 544.39  43521_BLACK_BURNER  50+0076KK   ERQW-BN66   Added
Rick    4147    10-34-2Z-73ABD      Gunrange    Robin   64234   -134.12 133.44  43521_BLACK_BURNER  32+003XX    HFDO-LW11   Deleted

如果我运行 Martin Evan 的代码 ,这就是我得到的结果

目前,我收到“TypeError: expected str, bytes, or os.PathLike object, not list。”当我将我拥有的代码与他的代码混合时出错。但是,如果我单独运行 Martin 的代码,我会得到如下图所示的 difference.csv,我猜 delimiter='\t' 是“历史”和“列”混淆的原因。我试图添加 2 个分隔符,希望它能将它们分开,但 python 不允许我这样做。另一方面,在谷歌搜索 TypeError 的解决方案后,我认为在 handle_uploaded_file 函数下使用 open() 方法可以解决问题,但它仍然存在,或者它可能不是正确的解决方案。非常感谢任何帮助

【问题讨论】:

  • 还有其他问题要问。如果一行或两行包含重复行,或者两行具有相同的Name 但不同的Citys,你会怎么做?如果订单有变怎么办?
  • 你可以有两个sets 元组和intersect 它们。首先是s1.intersection(s2),然后是s2.intersection(s1)。然后您将知道s1 中的值而不是s2 中的值,反之亦然
  • @AdamSmith 如果两个文件中有重复的行,例如 jack、mankato,则该信息将被跳过,因此,我没有将其写在diff.csv 中。如果两行名称相同但城市不同,则应相应打印并将其标记为“更改”
  • @RafaelC 如果我让 python 通过写入“with open('difference.csv', 'w') as outFile:”来读取文件,它仍然可以按照你所说的工作:或者我有手动输入元组本身的差异?
  • @J.Doe 哦,好的。所以这个问题的答案是:是的

标签: python django csv


【解决方案1】:

假设您不需要以某种方式处理old.csv 包含重复条目或new.csv 包含重复条目(即同一个名称在同一个文件中出现多次)的情况,那么正如建议的那样,一个实现这一点的方法是利用 Python 的集合。

通过从每个文件中创建一组名称,然后使用集合操作很容易确定添加、删除和更改。例如:

import csv

with open('old.csv', newline='') as f_old:
    csv_old = csv.reader(f_old, delimiter='\t')
    header = next(csv_old)
    old_data = {row[0] : row for row in csv_old}

with open('new.csv', newline='') as f_new:
    csv_new = csv.reader(f_new, delimiter='\t')
    header = next(csv_new)
    new_data = {row[0] : row for row in csv_new}

set_new_data = set(new_data)
set_old_data = set(old_data)

added = [['Added'] + new_data[v] for v in set_new_data - set_old_data]
deleted = [['Deleted'] + old_data[v] for v in set_old_data - set_new_data]
in_both = set_old_data & set_new_data
changed = [['Changed'] + new_data[v] for v in in_both if old_data[v] != new_data[v]]

with open('difference.csv', 'w', newline='') as f_output:
    csv_output = csv.writer(f_output, delimiter='\t')
    csv_output.writerow(['History'] + header)
    csv_output.writerows(sorted(added + deleted + changed, key=lambda x: x[1:]))

这会比较整行的差异。在 Python 3.6.3 上测试


尝试将此脚本添加到代码中的一个问题是 Python 3.x 中的 CSV 库需要使用 newline='' 参数打开文件(如果使用 2.x,则为二进制文件)。由于您的函数已经打开文件句柄,因此这是一个问题。请尝试以下操作:

import csv

def handle_uploaded_file(file_1, file_2): 
    """ handle_uploaded_file is a function that takes 2 files uploaded by the users """

    csv_old = csv.reader(file_1, delimiter='\t')
    header = next(csv_old)
    old_data = {row[0] : row for row in csv_old}

    csv_new = csv.reader(file_2, delimiter='\t')
    header = next(csv_new)
    new_data = {row[0] : row for row in csv_new}

    set_new_data = set(new_data)
    set_old_data = set(old_data)

    added = [['Added'] + new_data[v] for v in set_new_data - set_old_data]
    deleted = [['Deleted'] + old_data[v] for v in set_old_data - set_new_data]
    in_both = set_old_data & set_new_data
    changed = [['Changed'] + new_data[v] for v in in_both if old_data[v] != new_data[v]]

    with open('difference.csv', 'w', newline='') as f_output:
        csv_output = csv.writer(f_output, delimiter='\t')
        csv_output.writerow(['History'] + header)
        csv_output.writerows(sorted(added + deleted + changed, key=lambda x: x[1:]))

【讨论】:

  • 感谢您的回答,它仅适用于我制作的与图片相同的示例 csv 文件。当我使用教授给我的 csv 文件并且它们都包含 29k 记录时,程序给了我“,第 6 行,在 old_data = dict(csv_old) ValueError: dictionary update sequence element #0 has length 67; 2 is required”错误,我想知道我是否需要将“dict”更改为其他内容以使它们工作
  • 您需要edit 您的问题以显示您的 CSV 文件中重现问题的几个示例行。请将它们添加为原始文本,而不是图像。所需的脚本更改应该相当简单。还要显示它们需要什么输出格式。
  • 我完全编辑了问题,混合了你给我和我的代码,并展示了我正在寻找的示例,它仍然在图片中,我没有把它作为原始文本因为我想它更容易理解,但如果你想在原始文本中看到它,请告诉我,谢谢先生的帮助
  • 无法从图像中复制/粘贴数据,因此我无法轻松重现问题并测试修复。
  • 我在问题上添加了旧的、新的和不同的 csv 文件作为原始文本
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-27
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-05
  • 1970-01-01
相关资源
最近更新 更多