【问题标题】:Uploading single images across multiple HTML form inputs without Django Forms在没有 Django 表单的情况下跨多个 HTML 表单输入上传单个图像
【发布时间】:2021-11-24 01:01:40
【问题描述】:

我正在尝试创建数字名片 - 创建一个具有不同 HTML 表单输入的自定义可视化编辑器,以上传不同的图像,如个人资料、背景、徽标等,而无需 Django 表单。我可以让一个与使用两个字段的 Django 后端一起工作 - 一个用于图像名称,另一个是图像 URL。我希望为每个图像复制这个过程,直到我到达滑块部分。我仍在努力,因此设计不完整并使用测试数据。我附上了一张图片以供参考,以说明我正在尝试完成的工作,就像那里的测试数据一样愚蠢。

urls.py

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^icards/icard/edit/(?P<pk>\d+)/$', views.icard_edit, name='icard_edit'),
]

views.py

def icard_edit(request, pk):

    icard = Icard.objects.get(pk=pk)

    if request.method == 'POST':
        try:
            print("Try function reached")
            myfile = request.FILES['myfile']
            bg_myfile = request.FILES['bg_myfile']
            fs = FileSystemStorage()
            filename = fs.save(myfile.name, myfile)
            url = fs.url(filename)
            bg_filename = fs.save(bg_myfile.name, bg_myfile)
            bg_url = fs.url(bg_filename)

            if str(myfile.content_type).startswith("image") & str(bg_myfile.content_type).startswith("image"):

                if myfile.size < 5000000 & bg_myfile.size < 5000000:

                    b = Icard.objects.get(pk=pk)

                    fss = FileSystemStorage()
                    fss.delete(icard.logo)
                    fss.delete(icard.bg_image)

                    b.name = name
                    b.category = category
                    b.logo = filename
                    b.logo_url = url
                    b.bg_image = bg_filename
                    b.bg_url = bg_url
                    b.feature_one = feature_one

                    b.save()
                    print("func: Icard Data Edit Saved")
                    return redirect('icard_list')

                else:
                    fs = FileSystemStorage()
                    fs.delete(filename)
                    fs.delete(bg_filename)

                    error = "your File is Larger than 5 MB"
                    return render(request, 'back/error.html', {'error': error})

            else:
                fs = FileSystemStorage()
                fs.delete(filename)
                fs.delete(bg_filename)

                error = "Your File is not supported"
                return render(request, 'back/error.html', {'error': error})

        except:
            return redirect('icard_edit')

    return render(request, 'back/icards/icard_edit.html', {'pk': pk, 'icard': icard})

返回/icards/icard_edit.html

<form action="{% url 'icard_edit' pk=pk %}"
      method="post"
      enctype="multipart/form-data"
      class="form">
    {% csrf_token %}

    <div class="form-body">
        <div class="form-group">
            <label>Logo Image</label>
            <div class="input-group">

                <div class="custom-file">
                    <input type="file"
                           class="custom-file-input"
                           id="myfile"
                           name="myfile">
                    <label class="custom-file-label"
                           for="myfile">{{ icard.logo_url }}</label>
                </div>
            </div>
        </div>

        <div class="form-group text-right">
            <label><small>Background</small></label>
            <div class="input-group">

                <div class="custom-file text-left">
                    <input type="file"
                           class="custom-file-input"
                           id="bg_myfile"
                           name="bg_myfile">
                    <label class="custom-file-label"
                           for="bg_myfile">{{ icard.bg_url }}
                    </label>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="form-group">
            <button type="submit"
                    class="btn btn-outline-success">Submit</button>
        </div>
    </div>
</form>

错误:

Request Method: POST
Request URL: http://127.0.0.1:8000/icards/icard/edit/3/

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/datastructures.py", line 76, in __getitem__
    list_ = super().__getitem__(key)

During handling of the above exception ('myfile'), another exception occurred:
  File "/Volumes/1TB_Rocket/PycharmProjects/ibizcard_v1/icards/views.py", line 341, in icard_edit
    myfile = request.FILES['myfile']
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/datastructures.py", line 78, in __getitem__
    raise MultiValueDictKeyError(key)

During handling of the above exception ('myfile'), another exception occurred:
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Volumes/1TB_Rocket/PycharmProjects/ibizcard_v1/icards/views.py", line 397, in icard_edit
    return redirect('icard_edit')
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/shortcuts.py", line 41, in redirect
    return redirect_class(resolve_url(to, *args, **kwargs))
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/shortcuts.py", line 131, in resolve_url
    return reverse(to, args=args, kwargs=kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/urls/resolvers.py", line 677, in _reverse_with_prefix
    raise NoReverseMatch(msg)

Exception Type: NoReverseMatch at /icards/icard/edit/3/
Exception Value: Reverse for 'icard_edit' with no arguments not found. 1 pattern(s) tried: ['icards/icard/edit/(?P<pk>\\d+)/$']

【问题讨论】:

  • 是的,它在这里的主分支上github.com/xxroninCabxx/ibizcards/tree/main
  • 问题是我必须同时上传徽标和背景图片,否则会引发错误。我希望能够彼此独立地上传图像,或者如果已经上传了图像,它会看到它并且不必上传。所以我想我需要用另一个 if 和 try 语句在它现在所在的位置之外重构代码。

标签: python html django image


【解决方案1】:

使用request.FILES.get()if 语句来处理可选的图像上传。

# myfile = request.FILES['myfile']
# bg_myfile = request.FILES['bg_myfile']

myfile = request.FILES.get('myfile')
bg_myfile = request.FILES.get('bg_myfile')
# fss.delete(icard.logo)
# fss.delete(icard.bg_image)

# b.logo = filename
# b.logo_url = url
# b.bg_image = bg_filename
# b.bg_url = bg_url

if myfile:
    fss.delete(icard.logo)
    b.logo = filename
    b.logo_url = url

if bg_myfile:
    fss.delete(icard.bg_image)
    b.bg_image = bg_filename
    b.bg_url = bg_url

处理多张图片上传

以更易于维护的方式处理多个图像上传:

  • 避免“不支持”和“太大”检查的嵌套 if 语句。
  • 检查后保存文件(不依赖于保存的文件),而不是在检查失败时删除。
  • 返回未通过检查的文件名,以帮助用户了解要解决的问题。
  • 推迟fs.delete(),以便在icard.save() 失败时不会删除现有图像。
try:
    print("Try function reached")
    myfile = request.FILES.get('myfile')
    bg_myfile = request.FILES.get('bg_myfile')

    files_to_check = filter(None, [myfile, bg_myfile])

    filenames_not_supported = [file.name for file in files_to_check if not str(myfile.content_type).startswith("image")]
    if filenames_not_supported:
        error = "Your File is not supported: {}".format(filenames_not_supported)
        return render(request, 'back/error.html', {'error': error})

    filenames_too_large = [file.name for file in files_to_check if file.size >= 5000000]
    if filenames_too_large:
        error = "your File is Larger than 5 MB: {}".format(filenames_too_large)
        return render(request, 'back/error.html', {'error': error})

    fs = FileSystemStorage()
    filenames_to_delete = []

    if myfile:
        filenames_to_delete.append(icard.logo)
        icard.logo = fs.save(myfile.name, myfile)
        icard.logo_url = fs.url(icard.logo)

    if bg_myfile:
        filenames_to_delete.append(icard.bg_image)
        icard.bg_image = fs.save(bg_myfile.name, bg_myfile)
        icard.bg_url = fs.url(icard.bg_image)

    icard.name = name
    icard.category = category
    icard.feature_one = feature_one

    icard.save()
    print("func: Icard Data Edit Saved")

    for filename in filenames_to_delete:
        fs.delete(filename)

    return redirect('icard_list')

except Exception:
    return redirect('icard_edit', pk)

那么处理新的图片上传就简单明了:

profile = request.FILES.get('profile')

# files_to_check = filter(None, [myfile, bg_myfile])
files_to_check = filter(None, [myfile, bg_myfile, profile])

# ...

if profile:
    filenames_to_delete.append(icard.profile)
    icard.profile = fs.save(profile.name, profile)
    icard.profile_url = fs.url(icard.profile)

关于NoReverseMatch错误

URL 模式 r'^icards/icard/edit/(?P&lt;pk&gt;\d+)/$' 需要 pk

# return redirect('icard_edit')
return redirect('icard_edit', pk)

【讨论】:

  • 哦,亚伦,它工作得很好。非常感谢您,稍后我也会尝试其他图片上传!谢谢!
猜你喜欢
  • 2015-06-12
  • 2011-08-08
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-10-27
  • 2015-05-30
  • 2015-08-23
  • 1970-01-01
相关资源
最近更新 更多