自定義Excel匯入功能
阿新 • • 發佈:2019-01-02
例:
def import_data_from_excel(conf, filename, fk_name=None, fk_value=None, is_exchange=False): def valid_date(d): try: xlrd.xldate.xldate_as_datetime(d, 0) return True except: return False def check_field_with_input(field, i): t = type(field) choices = field.__dict__["choices"] if choices: for key, value in choices: if value == i.strip(): return True if field.__dict__["null"] is True and type(i) == unicode and not i.strip(): return True return False if t in [IntegerField, FloatField, ForeignKey]: return type(i) in [float, int] if t in [CharField, TextField]: return type(i) == unicode if field.__dict__["null"] is True and type(i) == unicode and not i.strip(): return True if t == DateField: return valid_date(i) return False # 檢查attributes, primary_keys, defaults 定義的資料列在表裡面 def check_conf(c): obj = create_instance(c) attrs = c["attributes"].keys() + c.get("primary_keys", []) if c.get("defaults", None): attrs = attrs + c["defaults"].keys() for k in attrs: if not hasattr(obj, k): print "{} has no attr '{}', please check.".format(c["class_name"], k) return False if fk_name: if not hasattr(obj, fk_name): print "{} has no foreign key '{}', please check.".format(c["class_name"], fk_name) return False return True def check_excel_input(c, sheet): rows_len, cols_len = sheet.nrows, sheet.ncols class_name = get_class(c) for r in range(1, rows_len): r_data = sheet.row_values(r) for k, v in c["attributes"].items(): if v > cols_len: return STRING_EXCEL_CONFIGURATION_EXCEEDS.format(cols_len, k, v) if not check_field_with_input(class_name._meta.get_field(k), r_data[v]): return STRING_EXCEL_LINE_INPUT_ERROR.format(r + 1, v, r_data[v]) return "success" def do_excel_input(c, sheet): item = get_class(c) rows_len, cols_len = sheet.nrows, sheet.ncols default_values = c.get("defaults", None) for r in range(1, rows_len): r_data = sheet.row_values(r) pks = conf.get("primary_keys", None) if pks: filter_dict = {} for pk in pks: field = item._meta.get_field(pk) choices = field.__dict__["choices"] if choices: for key, value in choices: if value == r_data[conf["attributes"][pk]]: filter_dict[pk] = key else: filter_dict[pk] = r_data[conf["attributes"][pk]] if fk_name and fk_value: filter_dict[fk_name] = fk_value rs = get_class(c).objects.filter(**filter_dict) d = rs[0] if len(rs) > 0 else create_instance(c) else: d = create_instance(c) for k, v in conf["attributes"].items(): if type(r_data[v]) == unicode and not str(r_data[v].strip()): continue field = d._meta.get_field(k) if type(field) == DateField: d.__setattr__(k, xlrd.xldate.xldate_as_datetime(r_data[v], 0)) elif field.__dict__["choices"]: for key, value in field.__dict__["choices"]: if value == r_data[v].strip(): d.__setattr__(k, key) else: d.__setattr__(k, r_data[v]) if fk_name and fk_value: d.__setattr__(fk_name, fk_value) # 此操作只用來對採購和發行的節目進行換片操作 if is_exchange and hasattr(d, "status"): d.__setattr__("status", 3) if default_values: for k, v in default_values.items(): # 對預設值的處理,對應若干歷史財務資料 d.__setattr__(k, v) d.save() if not check_conf(conf): return STRING_IMPORT_CONFIGURATION_ERROR sheet_index = conf.get("excel_sheet", 0) # print "System will import {} sheet".format(sheet_index) try: import_sheet = xlrd.open_workbook(filename).sheet_by_index(int(sheet_index)) except: return STRING_EXCEL_OPEN_ERROR try: check_input = check_excel_input(conf, import_sheet) if not check_input == "success": return check_input do_excel_input(conf, import_sheet) return STRING_EXCEL_IMPORT_SUCCESS except Exception as e: print e return STRING_EXCEL_GET_RECORDS_ERROR
ProductItemExcelImportConfig = { "module_name": "Product.models", "class_name": "ProductItem", "attributes": { "sn": 0, # 序號 "name": 1, # 節目名稱 "type": 2, # 類別 "theme": 3, # 型別 "episodes": 4, # 集數 "episodes_time": 5, # 單集時長 "total_time": 6, # 總時長 "clarity": 7, # 解析度 "play_time": 8, # 播出時間 "play_app": 9, # 播出平臺 "production_time": 10, # 出品年代 "area": 11, # 製片地區 "actor": 12, # 主演 "writers": 13, # 編劇 "director": 14, # 導演 "plots": 15, # 劇情介紹 "authorized_time": 16, # 授權開始日期 "authorized_end_time": 17, # 授權結束日期 "authorized_way": 18, # 授權方式 "authorized_area": 19, # 授權權利 "publish_licence": 20, # 發行許可證 "make_company": 21, # 製作機構 "up_copyright": 22, # 上游版權方 "copy_chain": 23, # 版權鏈 "site_limit": 24, # 站點限制 "item_status": 25, # 節目狀態 "remark": 27, # 備註 }, "primary_keys": ["name", "authorized_area", "up_copyright"], "defaults": { "item_source": '2', # 標示從Excel資料匯入 }, }
# 匯入可銷售節目 def import_product_items(request): try: path = get_upload_file_path() if request.method == 'POST': file_obj = request.FILES.get('file') # 判斷選擇檔案 if file_obj: filename = os.path.join(path, file_obj.name) file_type = str(os.path.splitext(filename)[1]) # 判斷檔案型別 if file_type in [".xls", ".xlsx"]: # 判斷檔案是否重名或者是否已經存在 if os.path.exists(filename): filename = filename + time.strftime(".%Y%m%d%H%M%S", time.localtime()) # 把上傳過來的檔案儲存 excel_file = open(filename, 'wb+') for file_data in file_obj.chunks(): excel_file.write(file_data) excel_file.close() r_url = "" res = import_data_from_excel(ProductItemExcelImportConfig, filename) result = {"statue": "success", "data": res} return JsonResponse(result) else: result = {"statue": "error", "data": "檔案格式不對,必須是 xls或xlsx"} return JsonResponse(result) else: result = {"statue": "error", "data": "你沒有選擇檔案呢!!!"} return JsonResponse(result) result = {"statue": "error", "data": "你沒有選擇檔案呢!!!"} return JsonResponse(result) except Exception as e: return render(request, 'error.html', locals())