Django后台文件上传并处理

2023-07-2715:36:49后端程序开发Comments729 views字数 7946阅读模式

本文分享自定义上传文件页面,接收文件后并处理的过程。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

Django后台文件上传并处理
效果

过程

用到了simpleui的自定义左侧导航功能。修改项目总的setting.py文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

setting.py

自定义左侧导航文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

SIMPLEUI_CONFIG = {
      # 是否使用系统默认菜单,自定义菜单时建议关闭。
     'system_keep': False,

      # 用于菜单排序和过滤, 不填此字段为默认排序和全部显示。空列表[] 为全部不显示.
     'menu_display': ['综合', '用户'],

     # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时刷新展示菜单内容。
     # 一般建议关闭。
     'dynamic': False,
     'menus': [
        {
             'app': 'auth',
             'name': '用户',
             'icon': 'fas fa-user-shield',
             'models': [
                {
                 'name': '用户列表',
                 'icon': 'fa fa-user',
                 'url': 'auth/user/'
                },
                {
                     'name': '用户组',
                     'icon': 'fa fa-th-list',
                     'url': 'auth/group/'
                }
            ]
        },

        {
             'name': '综合',
             'icon': 'fa fa-desktop',
             'models': [
                {
                 'name': '卡片管理',
                 'url': '/adm/general/virtualcard/',
                 'icon': 'fa fa-cog'
                },
                {
                 'name': '账单上传',
                 'url': '/record/upfrecord/',
                 'icon': 'fa fa-file-import'
                },
            ]
        },
    ]
 }

路由

修改项目模块目录下的url.py文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

from django.conf.urls import url
from record import views

urlpatterns = [
    url(r'^upfrecord/$', views.up_fundrecord_by_csv, name='record'),     #文件上传
]

处理

处理函数在views.py内定义,同样只允许管理员使用此接口。采用事物保证数据一致性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

@user_passes_test(lambda u: u.is_superuser)
@login_required
@transaction.atomic
def up_fundrecord_by_csv(request):
    """
    卡片流水记录处理函数
    """
    #未录入卡片
    not_import_vcards = []

    #处理条数
    suc=0
    repeat=0
    fail=0

    if request.method == 'POST':
        form = MyForm(request.POST, request.FILES)

        if form.is_valid():
            # 处理上传的文件
            uploaded_file = request.FILES['csvfile']
            if uploaded_file.name.endswith('.csv'):
                csv_data = uploaded_file.read().decode('utf-8')
                lines = csv_data.splitlines()
                reader = csv.reader(lines)

                #跳过表头
                next(reader)

                #遍历处理
                for row in reader:
                    #transid
                    vcard = VirtualCard.objects.filter(card_transid=row[0]).first()

                    if vcard:
                        #消费类型
                        if row[2] == 'Authorization(Purchase)':
                            record_type = 4
                        else:
                            record_type = 2

                        #时间
                        auth_at = row[7]
                        #金额
                        amount = Decimal(row[11])

                        datetime_obj = datetime.strptime(auth_at, '%Y-%m-%d %H:%M:%S')
                        timestamp = datetime_obj.timestamp()

                        unsign_str = str(amount)+vcard.currency+str(int(timestamp))+vcard.card_transid
                        md5str=common_utils_md5_sign_str(unsign_str)

                        #避免重复录入
                        fundrecord = FundRecord.objects.filter(record_md5=md5str).first()

                        if fundrecord:
                            repeat += 1
                        else:
                            #新增卡片消费记录
                            try:
                                with transaction.atomic():
                                    #交易状态为成功
                                    if row[3] == 'Success':
                                        #卡片流水记录
                                        fund_record = FundRecord.objects.create(
                                            card=vcard,
                                            record_md5=md5str,
                                            record_type=record_type,
                                            amount=amount,
                                            pos_currency=row[8],
                                            pos_amount=row[9],
                                            auth_at=auth_at,
                                            status=1,
                                        )

                                        #修改卡片余额
                                        if int(record_type)==4:
                                            vcard.settlement_amount += amount
                                            vcard.remaining_amount -= amount
                                        elif int(record_type)==2:
                                            vcard.settlement_amount -= amount
                                            vcard.remaining_amount  += amount
                                        vcard.save()

                                    else:
                                        fund_record = FundRecord.objects.create(
                                            card=vcard,
                                            record_md5=md5str,
                                            record_type=record_type,
                                            amount=amount,
                                            pos_currency=row[8],
                                            pos_amount=row[9],
                                            auth_at=auth_at,
                                            resmsg=row[5],
                                            status=2,
                                        )


                                    #记录处理成功
                                    suc += 1

                            except Exception as e:
                                fail += 1
                                logger.debug(e)

                    else:
                        not_import_vcards.append((row[0], row[1]))

            else:
                messages.error(request, '文件格式错误!')


        if fail > 0:
            messages.warning(request, '成功{}条,重复{}条,失败{}条'.format(suc,repeat,fail))
        else:
            messages.success(request, '成功{}条,重复{}条'.format(suc,repeat,fail))
    else:
        form = MyForm()

    content = {
        'title': '文件上传',
        'form': form,
        'not_import_vcards': list(set(not_import_vcards)),
        'suc': suc,
        'fail': fail,
    }

    return  render(request, 'admin/fundrecord_up.html', content)

模板文件

还有一个模板文件,用来接收csv格式的上传文件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html

{% extends 'admin/base_site.html' %}

{% block content %}
<div class="container" style="margin-bottom: 20px;">
    <h1>{{ title }}</h1>
    <form id="cardForm" method="post" action="" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <br><br>
        <button type="submit" class="el-btn el-btn--primary">确定</button>
    </form>
</div>

{% if not_import_vcards %}
<div style="height: 20px; border-top: 1px solid #000;">
</div>

<div style="margin-top: 20px;">
    <h2> 未在系统内发现下列虚拟卡, 请处理后重新上传:</h2>

    <table style="width: 100%; border-collapse: collapse;">
        <thead>
            <tr>
                <th style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd; background-color: #f2f2f2;">transid</th>
                <th style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd; background-color: #f2f2f2;">卡号</th>
                <th style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd; background-color: #f2f2f2;">操作</th>
            </tr>
        </thead>
        <tbody>
            {% for ncard in not_import_vcards %}
                <tr style="background-color: {% cycle 'white' 'lightgray' %};">
                    <td style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd;">{{ ncard.0 }}</td>
                    <td style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd;">{{ ncard.1 }}</td>
                    <td style="padding: 8px; text-align: left; border-bottom: 1px solid #ddd;"><button onclick="self.parent.app.openTab({'name':'添加新卡', 'icon': 'fas fa-user-tie', 'url':'/general/addcard/?ctid={{ ncard.0 }}'})"  class="el-button el-button--primary el-button--small">添加此卡</button></td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</div>
{% endif %}

{% endblock %}
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/52005.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/52005.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定