【问题标题】:Django dynamic FileField upload_toDjango 动态 FileField upload_to
【发布时间】:2018-11-08 12:27:38
【问题描述】:

我正在尝试为 FileField 模型创建动态上传路径。因此,当用户上传文件时,Django 会将其存储到我的计算机 /media/(username)/(path_to_a_file)/(filename) 中。

例如/media/Michael/Homeworks/Math/Week_1/questions.pdf 或 /media/Ernie/Fishing/Atlantic_ocean/Good_fishing_spots.txt

VIEWS
@login_required
def add_file(request, **kwargs):
if request.method == 'POST':
    form = AddFile(request.POST, request.FILES)
    if form.is_valid():
        post = form.save(commit=False)
        post.author = request.user

        post.parent = Directory.objects.get(directory_path=str(kwargs['directory_path']))
        post.file_path = str(kwargs['directory_path'])

        post.file_content = request.FILES['file_content'] <-- need to pass dynamic file_path here

        post.save()
        return redirect('/home/' + str(post.author))

MODELS
class File(models.Model):
    parent = models.ForeignKey(Directory, on_delete=models.CASCADE)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    file_name = models.CharField(max_length=100)
    file_path = models.CharField(max_length=900)
    file_content = models.FileField(upload_to='e.g. /username/PATH/PATH/..../')

FORMS
class AddFile(forms.ModelForm):
    class Meta:
        model = File
        fields = ['file_name', 'file_content']

我发现的是这个,但经过反复试验,我还没有找到方法。所以“上传/...”将是 post.file_path,它是动态的。

def get_upload_to(instance, filename):
    return 'upload/%d/%s' % (instance.profile, filename)


class Upload(models.Model):
    file = models.FileField(upload_to=get_upload_to)
    profile = models.ForeignKey(Profile, blank=True, null=True)

【问题讨论】:

    标签: django file-upload django-models filefield django-file-upload


    【解决方案1】:

    你可以使用这样的东西(我在我的项目中使用过):

    import os
    def get_upload_path(instance, filename):
        return os.path.join(
          "user_%d" % instance.owner.id, "car_%s" % instance.slug, filename)
    

    现在:

    photo = models.ImageField(upload_to=get_upload_path)
    

    【讨论】:

      【解决方案2】:

      由于file_pathFile 模型上的一个属性,你能不能像这样构建完整路径:

      import os
      
      def create_path(instance, filename):
          return os.path.join(
              instance.author.username,
              instance.file_path,
              filename
          )
      

      然后从您的File 模型中引用它:

      class File(models.Model):
          ...
          file_content = models.FileField(upload_to=create_path)
      

      Link to docs

      【讨论】:

      • filename 是两个词时,例如NRB 2708,最后是 NRB_2708。如何避免/覆盖下划线以结束 NRB 2708
      • @Gathide return filename.replace('_', ' ')
      【解决方案3】:

      其他答案完美无缺;但是,我想指出源代码中允许此类功能的行。可以在Django的源码中查看函数generate_filenamehere

      让魔法发生的台词:

      if callable(self.upload_to):
          filename = self.upload_to(instance, filename)
      

      当您将callable 传递给upload_to 参数时,Django 将调用callable 来生成路径。请注意,Django 期望您的 callable 处理两个参数:

      • instance
        • 包含FileField/ImageField的模型
      • filename
        • 上传文件的名称,包括扩展名(.png、.pdf、...)

      另请注意,Python 不会强制您的 callable 的参数完全是“实例”和“文件名”,因为 Django 将它们作为位置参数传递。例如,我更喜欢重命名它们:

      def get_file_path(obj, fname):
          return os.path.join(
              'products',
              obj.slug,
              fname,
          )
      

      然后像这样使用它:

      image = models.ImageField(upload_to=get_file_path)
      

      【讨论】:

        猜你喜欢
        • 2013-07-06
        • 2015-08-17
        • 1970-01-01
        • 1970-01-01
        • 2010-11-14
        • 1970-01-01
        • 2020-06-29
        • 1970-01-01
        相关资源
        最近更新 更多