1. 程式人生 > >自定義Excel匯入功能

自定義Excel匯入功能

例:

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())