Django:将用户上传保存在单独的文件夹中

Posted

技术标签:

【中文标题】Django:将用户上传保存在单独的文件夹中【英文标题】:Django: Save user uploads in seperate folders 【发布时间】:2016-03-18 07:56:21 【问题描述】:

我希望单个用户能够将他们的文件上传到单个文件夹中(因此每个用户都有自己的根文件夹,他们可以在其中上传自己的文件),但我不确定实施的最佳方式这个。

我原本打算用用户邮箱作为文件夹名,所有上传的内容都会保存在这个文件夹中。但是,根据我收集到的信息,检索此信息的唯一方法是通过请求函数,我无法将请求实例放入 models.py 文件中,因此无法将其添加到我的“upload_to”目录中。

任何其他关于如何分离用户文件或如何在模型文件中获取请求实例的想法将不胜感激!

这是我目前的模型:

def user_directory_path(instance, filename):
    return 'user_0/1'.format(instance.user.id, filename)

class UploadModel(models.Model):
    user = models.OneToOneField(User)
    file = models.FileField(upload_to=user_directory_path)

这是相关的错误:

Exception Value: UploadModel has no user.

【问题讨论】:

【参考方案1】:

对于将来偶然发现此问题的任何其他人,我通过将用户对象添加到视图中的模型来访问当前用户的 ID。

views.py

from .models import Document

if request.method == 'POST':
    form = DocumentForm(request.POST, request.FILES)
    if form.is_valid():
        newdoc = Document(docfile=request.FILES['docfile'])
        newdoc.owner = request.user
        newdoc.save()

然后,在 models.py 中,您可以从之前在视图中创建的所有者那里检索 ID。

def user_directory_path(instance, filename):
    return 'Users/user_0/1'.format(instance.owner.id, filename)


class Document(models.Model):
    docfile = models.FileField(upload_to=user_directory_path)

【讨论】:

【参考方案2】:

我也遇到了同样的问题。这是我解决它的方法。我们必须在视图中创建用户引用。

以下是 models.py

的代码
def user_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    return 'user_0/1'.format(instance.user.id, filename)

class Document(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
    docfile = models.FileField(upload_to=user_directory_path)
    date = models.DateTimeField(auto_now_add=True, blank=True)

同时更新views.py中的代码如下:

def upload(request):
    # Handle file upload
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            newdoc = Document(docfile=request.FILES['docfile'],user=request.user)
            newdoc.save()
            latest_documents = Document.objects.all().order_by('-id')[0]

            # Redirect to the document list after POST
            return HttpResponseRedirect(reverse('list'))
    else:
        form = DocumentForm()  # A empty, unbound form

    # Load documents for the list page
    documents = Document.objects.filter(user=request.user)

最重要的是排队,

newdoc = Document(docfile=request.FILES['docfile'],user=request.user)

不知何故,我无法让模型实例读取用户。这种方法对我有用。

【讨论】:

【参考方案3】:

为了让它发挥作用,我按照 Louis Barranqueiro 的建议实施了文档中的解决方案,模型如下所示:

# models.py
def user_directory_path(instance, filename):
    return 'user_0/1'.format(instance.user.id, filename)

class Document(models.Model):
    file = models.FileField(upload_to=user_directory_path)
    uploaded_at = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='documents')

但至关重要的是,我还更改了我的 DocumentUploadView 类以包含一个保存步骤,以便使用用户属性保存文档(还要注意初始的 commit=False 保存步骤,这很重要):

# views.py
class DocumentUploadView(View):

    def get(self, request):
        documents_list = Document.objects.all()
        return render(self.request, 'file_upload.html', 'documents': documents_list)

    def post(self, request):
        form = DocumentForm(self.request.POST, self.request.FILES)
        if form.is_valid():
            document = form.save(commit=False)
            document.user = request.user
            document.save()
            data = 'is_valid': True, 'name': document.file.name, 'url': document.file.url
        else:
            data = 'is_valid': False
        return JsonResponse(data)

最后我的 forms.py 看起来像这样:

# forms.py
class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
    fields = ('file',)

【讨论】:

【参考方案4】:

在您的 views.py 中,您必须像这样传递实例参数:

def post(self, request, *args, **kwargs):
    if 'uploadFile' in request.POST:
        f = UploadFileForm(request.POST, request.FILES, instance=request.user.uploadmodel)
        if f.is_valid():
            f.save()
            return HttpResponseRedirect('/sucess_url')

还有你的 forms.py

from django import forms

from .models import UploadForm


class UploadFileForm(forms.ModelForm):
    class Meta:
        model = UploadForm
        fields = ('file',)

【讨论】:

【参考方案5】:

你可以用他们的用户名分隔文件夹吗?您可以创建一个使用用户用户名创建文件夹的函数,如下所示:

def get_user_image_folder(instance, filename):
    return "%s/%s" %(instance.user.username, filename)

在您的模型中,您可以轻松地使用 upload_to 并将您刚刚创建的函数添加到其中:

class Images(models.Model):
   user = models.ForeignKey(User)
   image = models.ImageField(upload_to=get_user_image_folder,
                                  verbose_name='Image', )

您不必在模型中使用request,而是使用instance

【讨论】:

您好,我已经应用了这个,但我收到错误:“异常值:UploadModel 没有用户”,添加到我的问题中。 哦,当我不使用用户变量时,我会收到错误:“table Core_uploadmodel 没有名为 user_id 的列”,不知道该去哪里。 我更新了我的答案@Kane,我认为您需要在 UploadModel 中添加一个用户字段作为 FK。尝试一下,不要忘记迁移以更新您的数据库。【参考方案6】:

    我不建议您使用用户电子邮件或任何其他可以更新的信息作为文件夹名称,因为您不会在每次他更改电子邮件或用户名时更改文件夹名称。因此,请使用唯一且不可更改的用户 ID。

    这是一个来自 Django 文档的完整示例,用于访问模型中的实例信息以使用用户 ID 构建路径:

def user_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    return 'user_0/1'.format(instance.user.id, filename)

class MyModel(models.Model):
    upload = models.FileField(upload_to=user_directory_path)

在这种情况下,它使用文件夹名称中的用户 ID。当然,您可以将FileField 替换为ImageField

django 文档中的更多信息:FileFields.upload_to

【讨论】:

1.嗯,好点,那我就用用户ID。 2. 我遇到过这个但收到一个错误并忘记了它。但是现在我再次应用了它,但是我仍然收到相同的错误:“'UploadModel' 对象没有属性'user'”其中'UploadModel' 是包含我的 FileField 的模型 我给你一个例子,如果你想添加所有相关的模型,我给你一个具体的例子。 instance 代表当前对象,如果您的模型是您的用户模型,则使用instance.id。当当前模型与默认用户模型有OneToOneField 关系时,使用instance.user.id 好的,添加“user = models.OneToOneField(User)”是否正确?因为这引发了一个错误('UploadModel' 没有用户),所以我觉得我错过了一些东西。抱歉,我是 Django 新手,请原谅新手问题。 请在您的问题中添加您的模型并精确错误 你迁移和迁移了吗?

以上是关于Django:将用户上传保存在单独的文件夹中的主要内容,如果未能解决你的问题,请参考以下文章

带有单独提交和上传按钮的 Django 应用程序

使用单独的输入在表单上上传 2 个单个文件:Django

django如何取用户上传的头像

将通过 ajax 上传的文件保存到 Django 模型 ImageField

Django 用户配置文件

Django中对于上传的文件的保存方法(时间+文件名)