【问题标题】:How do I get a files absolute path after being uploaded in Django?在 Django 中上传后如何获取文件的绝对路径?
【发布时间】:2017-07-21 12:51:15
【问题描述】:

我想上传一个文件到我的数据库,上传后导入它并最终将数据导出到我的数据库中。我的上传工作正常,但我不确定如何在上传文件后获取文件的绝对路径。我可以打印出文档的名称,但如果上传了相同的文档名称,它会被附加,但如果我调用form.cleaned_data['document'].name,它仍会显示原始文件名。如何获取绝对文件路径,然后调用函数开始处理此文件?

所以这就是我想要做的:

  • 用户上传 .csv 文件
  • 文件保存在 db 中(带有描述和文件路径。文件路径已正确存储在 db 中)
  • 获取刚刚上传的文件的文件位置
  • 开始处理此文件以转换 .csv 数据并存储在数据库中

models.py

from django.db import models

# Create your models here.
class Document(models.Model):
    description = models.CharField(max_length=255, blank=True)
    document = models.FileField(upload_to='documents/')
    uploaded_at = models.DateTimeField(auto_now_add=True)

views.py

from django.shortcuts import render, redirect
from django.views import View
# Create your views here.

from .forms import DocumentForm
from .models import Document   

class  FileUpload(View):
    def post(self, request):
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            print()
            print(form.cleaned_data['document'].name)
            form.save()
            return redirect('main_db_model:home')
        else:
            return render(request, 'file_upload_form.html', {
                'form': form
            })

    def get(self, request):
        form = DocumentForm()
        return render(request, 'file_upload_form.html', {
            'form': form
        })

forms.py

from django import forms
from .models import Document

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ('description', 'document', )

file_upload_form.html(模板):

{% extends "base.html" %}

{% block content %}
  <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Upload</button>
  </form>
      {% if saved %}
         <strong>Your profile was saved.</strong>
      {% endif %}
  This is the form page
  <p><a href="{% url 'main_db_model:home' %}">Return to home</a></p>

    <p>Uploaded files:</p>
      <ul>
        {% for obj in documents %}
          <li>
            <a href="{{ obj.document.url }}">{{ obj.document.name }}</a>
            <small>(Uploaded at: {{ obj.uploaded_at }})</small>
            {{ obj.document.url }}
          </li>
        {% endfor %}
      </ul>
{% endblock %}

【问题讨论】:

    标签: python django django-models django-forms django-views


    【解决方案1】:

    之前建议你把这个upload_to='documents/'改成upload_to='documents/%Y/%m/%d',为什么?这可以处理documents/ 路径中的巨大文档文件。


    form.cleaned_data['document'](或request.FILES['document'])返回一个UploadedFile 对象。当然form.cleaned_data['document'].name 应该只返回一个名字。

    class  FileUpload(View):
        def post(self, request):
            form = DocumentForm(request.POST, request.FILES)
            if form.is_valid():
                # this `initial_obj` if you need to update before it uploaded.
                # such as `initial_obj.user = request.user` if you has fk to `User`, 
                # if not you can only using `obj = form.save()`
                initial_obj = form.save(commit=False)
                initial_obj.save()
    
                # return path name from `upload_to='documents/'` in your `models.py` + absolute path of file.
                # eg; `documents/filename.csv`
                print(initial_obj.document)
    
                # return `MEDIA_URL` + `upload_to` + absolute path of file.
                # eg; `/media/documents/filename.csv`
                print(initial_obj.document.url)
    
                form.save()
    

    但是如果你使用upload_to='documents/%Y/%m/%d',你会得到不同的,

    print(initial_obj.document)      # `documents/2017/02/29/filename.csv`
    
    print(initial_obj.document.url)  # `/media/documents/2017/02/29/filename.csv`
    

    【讨论】:

    • 非常感谢您的解释。我会采用这种方法,因为它最有意义!
    【解决方案2】:

    如果您尝试从实际的 Django 表单中保存文件,答案会很好。但是,也许有人(比如我)从 REST API 上下文中偶然发现了这个问题。因此,在处理 REST api 文件上传 post 请求的上下文中,以下是 django==3.2 对我有用的方法:

        from django.core.files.storage import FileSystemStorage
        img_file = request.FILES['file']
        
        fs = FileSystemStorage()
        filename = fs.save(img_file.name, img_file)
        uploaded_file_path = fs.path(filename)
        print('absolute file path', uploaded_file_path)    
    

    所以,fs.path(filename) 实际上返回了我刚刚上传的文件的绝对路径。例如:在我的情况下,我的应用程序在 debian docker 容器中运行,我的媒体目录是 /vol/web/media 并且我得到像 /vol/web/media/myfile.jpg 这样的输出,这正是我想要。

    【讨论】:

      【解决方案3】:

      我觉得上传文件后获取路径比较好,下面是使用create方法(model.objects.create())的例子

      models.py

      class AuctionPurchase(models.Model):
          file = models.FileField( upload_to='auction_purchase_files/')
          file_name = models.CharField(max_length=255)
          updated = models.DateTimeField(auto_now=True)
          timestamp = models.DateTimeField(auto_now_add=True)
          
          def __str__(self):
              return self.file_name
          
          class Meta:
              ordering = ["-timestamp", ]
      

      views.py

      def auction_purchases_upload(request):
          template_name = 'auction_purchases/auction_purchases_upload.html'
          if request.method == 'POST':
              file = request.FILES.get('file')
              file_obj = AuctionPurchase.objects.create(
                  file=file,
                  file_name = file.name
              )
              file_path = '/media/'+ str(file_obj.file)
              Print(file_path)
              messages.success(request, 'File successfully upload.')
              return redirect('auction_purchases:auction_purchases_upload')
          form = AuctionPurchaseForm()
          return render(request, template_name,{'form':form})
      

      在视图中,我们可以使用 create 方法返回创建对象的实例,该对象可以使用模型字段名称访问,例如 file_obj.file 为您提供了保存的相对路径,我只需要将媒体文件夹附加到制作 路径完整,要获得绝对路径,只需执行file_obj.file.path

      【讨论】:

        猜你喜欢
        • 2010-11-20
        • 2017-02-20
        • 2016-11-19
        • 2022-12-07
        • 1970-01-01
        • 2010-09-08
        • 1970-01-01
        相关资源
        最近更新 更多