【问题标题】:Set ImageField default value to random image out of a list of images in Django将 ImageField 默认值设置为 Django 中图像列表中的随机图像
【发布时间】:2015-06-14 13:38:39
【问题描述】:

我在静态目录中有一些图像,并想创建一个具有 ImageField 的模型。我想将默认字段设置为这些图像中的任何一个。我试过用这个 -

def randomImage():
    return ImageFile('media/blog/image/' + str(random.randrange(1, 15, 1)) + '.jpg')

# ----------------------- Model for each post in the blog-------------------
class Post(models.Model):
    heading = models.CharField(max_length=150)
    author = models.ForeignKey(User)
    postBody = models.TextField()
    postDate = models.DateTimeField('posting date')
    postImage = models.ImageField(upload_to='media/blog/image/'+str(int(time.time())), default=randomImage)

【问题讨论】:

  • @abidibo 不,上面的链接没有告诉任何关于使用随机图像路径生成函数的信息。我想要的是使用一个返回随机图像路径的函数,然后将其设置为该记录的图像。
  • 我对此悬赏,因为这个问题没有答案,而且链接的答案完全不相关。
  • @Routhinator 我已经添加了一个答案,试试吧:)
  • @JPG 看看,一旦我确认它运作良好,将奖励赏金。 :)

标签: python django random django-models imagefield


【解决方案1】:

我在这里做一些假设,
1. 您的默认图片位于 static 目录中
2. static 目录内,所有文件都是图片

这里的主要技巧是什么?

Django 只需要一个有效的文件路径来创建或更新一个文件条目(图像也是一个文件)。所以,我们在这里所做的是,列出所有文件(假设这些只是图像)并使用random.choice() 随机选取一个条目并重新调整 绝对路径(类似于 static/my_img.jpg)到 default 参数

import time
from random import choice
from os.path import join as path_join
from os import listdir
from os.path import isfile


def random_img():
    dir_path = 'static'
    files = [content for content in listdir(dir_path) if isfile(path_join(dir_path, content))]
    return path_join(dir_path, choice(files))


class Post(models.Model):
    # other fields
    postImage = models.ImageField(
        upload_to='media/blog/image/' + str(int(time.time())),
        default=random_img)



更新-1

我在 Django 2.1.1 中创建了一个最小示例,可以在以下 git repo 中找到它
存储库链接 -> django2X
1.克隆存储库,创建一个虚拟环境并安装依赖项(提供requirements.txt文件)
2.创建一个新的超级用户或使用我的(用户名->admin,pass->jerin123@)
3.运行服务器并登录django admin:(screenshot-1)
4. 创建一个新的Post 实例(一次又一次)

而已

更新-2

我在我的最小示例中做了一些更改,它们是
1. 创建一个简单的对象创建(这里是 Post 模型对象)在每次 django 启动时(结帐sample/app.py)
2、settings.py文件新增MEDIA_ROOT和MEDIA_URL

现在,启动您的项目(每次启动将创建 3 个对象)并转到 http://127.0.0.1:8000/admin/sample/post/。
然后打开任何实例并单击图像链接 (screenshot-2),它将打开图像 (screenshot-3 )

【讨论】:

  • 看起来这行不通。 Django 在调用 django.start() 时执行 random 函数,这是在收集静态之前。如果文件不存在,它会获得我添加的默认响应,然后静态地使用该响应作为默认设置。它不会调用model.save()上的函数,导致函数无用。
  • 也许我说得太早了。它适用于应用程序启动后注册的新用户,但不适用于在启动时从初始导入中保存的用户。试图找出原因。
  • 初始导入是什么意思。我不明白这一点
  • 我正在将现有站点迁移到 Django。在我的 startup.py 脚本中运行静态文件收集和迁移后,我运行一个名为“installlegacy”的自定义管理命令,该命令检查是否已导入用户和数据。这使用遗留数据库连接从旧数据库中获取用户对象,然后将它们的属性映射到新用户模型,然后调用 user.save() - 在此过程中由于某种原因,该函数无法找到任何图像,即使已经收集了静态文件。
  • 为了给你一个完整的画面,我已经创建了启动脚本的sn-ps、导入过程、你的示例的修改版本和成员的models.py。 random_img() 函数设置为背景图像的默认值:gitlab.routh.io/users/Routhinator/snippets
【解决方案2】:

我的解决方案是覆盖模型保存方法并检查模型是否是第一次创建并检查 postImage 图像字段是否为空。如果是这样用随机图像的内容填充 postImage 字段。 Django 会处理剩下的事情

如果我们直接在模型中使用随机图像的路径,我们最终会像从媒体文件夹和静态目录中提供一些后期模型文件一样,这是不推荐的。相反,我们将图像文件内容提供给 postImage 字段,Django 会将图像保存到媒体文件夹,因此我们可以从媒体文件夹本身提供所有模型图像。沃拉

代码

以下代码在 Python 3.6 中测试 请将代码添加到您的 models.py

from pathlib import Path
from random import randint
import time
from django.core.files import File
from django.db import models

allowed_image_extensions = ['.jpg', '.png', '.jpeg']


def get_file_extension(file_path):
    return Path(file_path).suffix


def get_files_in_directory(directory, absolute_path=False):
    from os import listdir
    from os.path import isfile
    only_files = [f for f in listdir(directory) if isfile("{}/{}".format(directory, f))]

    if not absolute_path:
        return only_files

    else:
        return ["{}/{}".format(directory, file_) for file_ in only_files]


def get_random_image_from_directory(directory_path, image_extension=None):
    files_in_directory_path = get_files_in_directory(directory_path, absolute_path=True)

    if image_extension:
        allowed_file_types = [image_extension]
    else:
        allowed_file_types = allowed_image_extensions

    # filter out files of type other than required file types
    filtered_files_list = [_file for _file in files_in_directory_path if
                       get_file_extension(_file).lower() in allowed_file_types]

   random_index = randint(0, len(filtered_files_list) - 1)
   random_file_path = filtered_files_list[random_index]
   random_file_content = File(open(random_file_path, 'rb'))

   return random_file_content


def get_post_image_path(instance, filename):
    path_first_component = 'posts'
    ext = get_file_extension(filename)
    current_time_stamp = int(time.time())
    file_name = '{}/posts_{}_{}{}'.format(path_first_component, instance.id, current_time_stamp, ext)
    full_path = path_first_component + file_name
    return full_path

class Post(models.Model):
    heading = models.CharField(max_length=150)
    author = models.ForeignKey(User)
    postBody = models.TextField()
    postDate = models.DateTimeField('posting date')
    postImage = models.ImageField(blank=True, null=True, upload_to=get_post_image_path)

    # override model save method
    def save(self, *args, **kwargs):

        # check model is new and postImage is empty
        if self.pk is None and not self.postImage:
            random_image = get_random_image_from_directory(settings.STATIC_ROOT)
            self.postImage = random_image
            random_image.close()


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

也无需在upload_to 路径中设置'/media'。 Django 将从设置变量中读取媒体路径

最佳做法是将这些默认图像集从静态目录移到另一个文件夹,可能是另一个具有名称资源或任何其他有意义名称的文件夹,因为随着项目的增长,静态目录内容会经常更改

【讨论】:

  • 将对此进行测试,我认为这将强制在保存时实际调用随机图像。我认为 @JPG 的方法发生的情况是,当 django 加载模型时,每次执行都会调用一次,所以我的导入只在收集静态文件之前执行一次,然后为每个用户使用失败结果。而这将在每次调用保存时被强制调用,并且将一直有效。
  • 啊,这段代码不能免疫django.core.exceptions.SuspiciousFileOperation: The joined path (/usr/src/app/static/images/avatars/wolf_avatar1.jpg) is located outside of the base path component (/usr/src/app/media)
  • 设法让它通过一个小的变化工作:.self.postImage.save( str(self.postDate) + get_file_extension(random_image.name), random_image, save=True)
  • 获得赏金。这似乎是适用于每个模型保存的最强大的解决方案。请用所需的小修改更新您的答案。
  • 另外两个小修改。在这一行中,您正在创建一个列表列表,这会导致扩展过滤器过滤掉所有内容,即使是有效的。它应该是allowed_file_types = allowed_image_extensions(var 周围没有 []),并且需要绝对路径,所以在模型保存中我们实际上应该使用 django 设置调用它。STATIC_ROOT var:get_random_image_from_directory(settings.STATIC_ROOT)
猜你喜欢
  • 2010-11-19
  • 1970-01-01
  • 2021-05-26
  • 2023-03-19
  • 2014-09-01
  • 1970-01-01
  • 2014-12-03
  • 2021-08-16
  • 2014-02-11
相关资源
最近更新 更多