Django-上传图片时使用instance.id

7dl7o3gd  于 2022-10-02  发布在  Go
关注(0)|答案(3)|浏览(156)

我指的是这个youtube video,以了解如何使用Imagefield上传图像。他解释了如何在保存图像的同时使用instance.id。我尝试过,但instance.id返回None。而对他来说,这一切都是完美的。以下是代码:


# models.py

import os

def get_image_path(instance, filename):
    return os.path.join(str(instance.id), filename)

class AdProfile(models.Model):
    name = models.CharField(max_length=100)
    profile_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)

无论何时保存文件,都会将其另存为None/filename

即使这个link也传达了同样的信息。我使用的是Django 10.5和MySQL数据库。

问题可能出在哪里?

5vf7fwbs

5vf7fwbs1#

Django admin在没有将模型保存到数据库的情况下调用了GET_IMAGE_PATH函数,因此id为None。我们可以使用保存方法覆盖Django模型,并确保保存了图像,并使用GET_IMAGE_PATH获取具有id的示例

class AdProfile(models.Model):
    name = models.CharField(max_length=100)
    profile_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)

    # Model Save override 
    def save(self, *args,**kwargs):
        if self.id is None:
            saved_image = self.profile_image
            self.profile_image = None
            super(AdProfile, self).save(*args,**kwargs)
            self.profile_image = saved_image
            if 'force_insert' in kwargs:
                kwargs.pop('force_insert')

        super(AdProfile, self).save(*args,**kwargs)
2ekbmq32

2ekbmq322#

根据Raja Simon的回答,有一些方法可以处理模型中的所有FileField

class MyModel(models.Model):

    file_field = models.FileField(upload_to=upload_to, blank=True, null=True)

    def save(self, *args,**kwargs):
        if self.id is None:
            saved = []
            for f in self.__class__._meta.get_fields():
                if isinstance(f, models.FileField):
                    saved.append((f.name, getattr(self, f.name)))
                    setattr(self, f.name, None)

            super(self.__class__, self).save(*args,**kwargs)

            for name, val in saved:
                setattr(self, name, val)
        super(self.__class__, self).save(*args,**kwargs)

此外,我们可以使文件位置动态,即不仅基于self.id,而且还基于外键ID或其他任何东西。只需迭代字段并检查路径是否更改。

def upload_to(o, fn):
    if o.parent and o.parent.id:
        return parent_upload_to(o.parent, fn)

    return "my_temp_dir/{}/{}".format(o.id, fn)

class MyModel(models.Model):

    parent = models.ForeignKey(Parent)

    def save(self, *args,**kwargs):

        # .... code from save() above here

        for f in [f for f in self.__class__._meta.get_fields() if isinstance(f, models.FileField)]:

            upload_to = f.upload_to

            f = getattr(self, f.name)  # f is FileField now

            if f and callable(upload_to):
                _, fn = os.path.split(f.name)
                old_name = os.path.normpath(f.name)
                new_name = os.path.normpath(upload_to(self, fn))

                if old_name != new_name:

                    old_path = os.path.join(settings.MEDIA_ROOT, old_name)
                    new_path = os.path.join(settings.MEDIA_ROOT, new_name)

                    new_dir, _ = os.path.split(new_path)
                    if not os.path.exists(new_dir):
                        print "Making  dir {}", new_dir
                        os.makedirs(new_dir)

                    print "Moving {} to {}".format(old_path, new_path)
                    try:
                        os.rename(old_path, new_path)
                        f.name = new_name

                    except WindowsError as e:
                        print "Can not move file, WindowsError: {}".format(e)

        super(self.__class__, self).save(*args,**kwargs)
kzmpq1sx

kzmpq1sx3#

您可以通过将清理后的数据从表单以**kwargs的形式传递给Django模型来创建模型示例。我就是这样做的,这比其他任何方法都简单得多

我根据所有者字段命名路径,该字段引用Django的用户模型

在您的视图中,POST方法添加这个(此代码来自我的项目,不适用于这个问题)

pk = request.session['_auth_user_id']
    user_obj = User.objects.get(pk=pk)

    lab_form_instance = lab_form(request.POST,request.FILES)
    lab_form_instance.save(commit=False)
    # here you can put the form.is_valid() statement
    lab_form_instance.cleaned_data['owner'] =user_obj # here iam adding additional needed data for the model
    obj = lab(**lab_form_instance.cleaned_data)
    obj.save()
  • Django==4.1

相关问题