【问题标题】:How to restore sqlite3 database file programmatically in django如何在 django 中以编程方式恢复 sqlite3 数据库文件
【发布时间】:2020-06-23 13:20:53
【问题描述】:

用户希望通过应用程序拥有数据库备份和恢复功能。他们希望能够下载数据库文件并将其上传以在需要时恢复数据库。问题是 django 已经在运行当前的数据库文件。我写了以下逻辑来恢复数据库。

    folder ='./' 
if request.method == 'POST':        
    myfile = request.FILES['file']
    fs = FileSystemStorage(location=folder) 
    if myfile.name.split(".")[1] != "sqlite3":
        return JsonResponse({"res":"Please upload a database file."})
    if os.path.isfile(os.path.join(folder, "db.sqlite3")): 
        os.remove(os.path.join(folder, "db.sqlite3"))        
    filename = fs.save("db.sqlite3", myfile)
    file_url = fs.url(filename)
    return JsonResponse({"res":file_url})

我得到以下正确的错误:

[WinError 32] 进程无法访问该文件,因为它正被另一个进程使用

那么,有没有办法通过我的应用程序来实现这个功能?

【问题讨论】:

    标签: django sqlite


    【解决方案1】:

    我找到了使用 csv 创建此功能的更好方法。可以将数据库中的数据存储到 csv 文件中,并在上传时恢复。以下是我的实现:

        def back_up_done(request):
            tables = getTableNames()
            sql3_cursor = connection.cursor()
            for table in tables:
                sql3_cursor.execute(f'SELECT * FROM {table}')
                with open('output.csv','a') as out_csv_file:
                    csv_out = csv.writer(out_csv_file)
        
                    for result in sql3_cursor:
                        csv_out.writerow('Null' if x is None else x for x in result)
                    csv_out.writerow("|")
        
            BaseDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            csv_path = os.path.join(BaseDir, 'output.csv')
            dbfile = File(open(csv_path, "rb"))
        
            response = HttpResponse(dbfile, content_type='application/csv')
            response['Content-Disposition'] = 'attachment; filename=%s' % 'backup.csv'
            response['Content-Length'] = dbfile.size
            os.remove(os.path.join("./", "output.csv"))
            return response
    
    
    def back_up_restore(request):
        if request.method == 'POST':        
            DBfile = request.FILES['file']
            cursor = connection.cursor()
            
            if DBfile.name.split(".")[1] != "csv":
                messages.add_message(request, messages.ERROR, "Please upload a CSV file.")
                return redirect('back-up-db')
    
            tables = getTableNames()
            i = 0
            deleteColumns()
            decoded_file = DBfile.read().decode('utf-8').splitlines()
            reader = csv.reader(decoded_file)
    
            for row in reader:
                if len(row) != 0:
                    if(row[0] == "|"):
                        i += 1
                    else:
                        query = f'''Insert into {tables[i]} values({concatRowValues(row)})'''
                        
                        cursor.execute(query)
            connection.close()
            messages.add_message(request, messages.SUCCESS, "Data Restored Successfully.")
            return redirect('login')
    
    def concatRowValues(row):
        data = ''
        for i,value in enumerate(row):
            if value == "False":
                value = '0'
            elif value == "True":
                value = '1'    
            
            if i != len(row) - 1:
                data =  f'{data}{str(value)},' if value == "Null" else f'{data}\'{str(value)}\','
            else:
                data = f'{data}{str(value)}' if value == "Null" else f'{data}\'{str(value)}\''
        return data
    

    其中 getTableNames 和 concatRowValues 是帮助函数,分别用于获取表的名称并连接列值以形成可执行的 sql 语句。 “|”字符用于标记表数据的结束。

    【讨论】:

      猜你喜欢
      • 2017-07-27
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      • 2013-08-18
      • 1970-01-01
      相关资源
      最近更新 更多