3

我有两个模型,RoomImageImage是一个通用模型,可以附加到任何其他模型上。我想在用户发布有关房间的信息时为用户提供一个表单来上传图像。我已经编写了有效的代码,但恐怕我已经以一种艰难的方式完成了它,特别是以违反 DRY 的方式。

希望对django表单更熟悉的人能指出我哪里出错了。

更新:

我试图澄清为什么我在对当前答案的评论中选择了这个设计。总结一下:

我并没有简单地ImageFieldRoom模型上放置一个,因为我想要多个与 Room 模型相关联的图像。我选择了一个通用的 Image 模型,因为我想将图像添加到几个不同的模型中。我考虑的替代方案是单个Image类上的多个外键,这看起来很混乱,或者多个Image类,我认为这会使我的架构混乱。我在第一篇文章中没有说清楚,对此我深表歉意。

看到到目前为止没有一个答案解决了如何使这个更干燥的问题,我确实提出了自己的解决方案,即将上传路径作为类属性添加到图像模型上,并在每次需要时引用它。

# Models
class Image(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    image = models.ImageField(_('Image'),
                                height_field='',
                                width_field='',
                                upload_to='uploads/images',
                                max_length=200)
class Room(models.Model):
    name = models.CharField(max_length=50)
    image_set = generic.GenericRelation('Image') 

# The form
class AddRoomForm(forms.ModelForm):
    image_1 = forms.ImageField()

    class Meta:
        model = Room

# The view
def handle_uploaded_file(f):

    # DRY violation, I've already specified the upload path in the image model
    upload_suffix = join('uploads/images', f.name)
    upload_path = join(settings.MEDIA_ROOT, upload_suffix)
    destination = open(upload_path, 'wb+')
    for chunk in f.chunks():
        destination.write(chunk)
    destination.close()
    return upload_suffix

def add_room(request, apartment_id, form_class=AddRoomForm, template='apartments/add_room.html'):
    apartment  = Apartment.objects.get(id=apartment_id)

    if request.method == 'POST':
        form = form_class(request.POST, request.FILES)
        if form.is_valid():
            room = form.save()
            image_1 = form.cleaned_data['image_1']

            # Instead of writing a special function to handle the image, 
            # shouldn't I just be able to pass it straight into Image.objects.create
            # ...but it doesn't seem to work for some reason, wrong syntax perhaps?

            upload_path = handle_uploaded_file(image_1)
            image = Image.objects.create(content_object=room, image=upload_path)
            return HttpResponseRedirect(room.get_absolute_url())
    else:
        form = form_class()
    context = {'form': form, }
    return direct_to_template(request, template, extra_context=context)
4

7 回答 7

4

你为什么不直接使用ImageField?我不认为需要Image上课。

# model
class Room(models.Model):
    name = models.CharField(max_length=50)
    image = models.ImageField(upload_to="uploads/images/")

# form
from django import forms

class UploadFileForm(forms.Form):
    name = forms.CharField(max_length=50)
    image  = forms.FileField()

查看基本文件上传如何使用图像和文件字段?

于 2009-01-22T11:39:09.097 回答
2

您不必使用 Image 类。正如DZPM建议的那样,将图像字段转换为 ImageField。您还需要对视图进行一些更改。

您可以使用上传的数据创建一个 Image 对象,并将 Image 对象附加到 Room 对象,而不是使用上传处理程序。

要保存 Image 对象,您需要在视图中执行以下操作:

from django.core.files.base import ContentFile

if request.FILES.has_key('image_1'):
    image_obj = Image()
    image_obj.file.save(request.FILES['image_1'].name,\
                        ContentFile(request.FILES['image_1'].read()))
    image_obj.save()
    room_obj.image_set.create(image_obj)
    room_obj.save()

另外,我认为您应该使用 ManyToManyField 而不是 GenericRelation,在这种情况下,将图像添加到 Room 的语法会略有变化。

于 2009-01-22T12:12:45.270 回答
0

在页面上使用两种形式怎么样:一种用于房间,一种用于图像?

您只需要使图像表单的通用外键字段不需要,并在保存房间后在视图中填写它们的值。

于 2009-02-10T08:28:03.543 回答
0

Django 至少在一定程度上支持您的用例:

  • 表单集显示重复的表单
  • 模型表单集处理重复的模型表单
  • 内联表单集将模型表单集绑定到实例的相关对象
  • 通用内联表单集对通用关系做同样的事情

在变更集 [8279]中引入了通用内联表单集。查看单元测试的更改以了解它们是如何使用的。

使用通用内联表单集,您还可以在表单中显示多个已保存的现有房间图像。

内联表单集似乎期望instance=参数中有一个现有的父实例。管理界面确实允许您在保存父实例之前填写内联,因此必须有一种方法来实现这一点。我自己从未尝试过。

于 2009-02-10T08:38:50.193 回答
0

我发现这个页面寻找解决同样问题的方法。

这是我的信息-希望对一些人有所帮助。

模型:图像、评论、制造商、简介

我希望 Review、Manufacturer、Profile 与 Image 模型有关系。但是您必须能够为每个对象提供多个图像。(即,一个评论可以有 5 张图片,而不同的评论可以有 3 张,等等)

最初我做了一个

images = ManyToManyField(Image)

在其他每个模型中。这很好用,但对管理员来说很糟糕(组合选择框)。不过,这可能是您的解决方案。我不喜欢我正在尝试做的事情。

我现在正在做的另一件事是拥有多个外键。

class Image(models.Model):
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to="media/")
    user_profile = models.ForeignKey(UserProfile)
    mfgr = models.ForeignKey(Manufacturer)
    review = models.ForeignKey(Review)

但就像你说的。这看起来很草率,我只是不喜欢它。

我刚刚发现的另一件事,但我的大脑并没有完全包裹(并且不确定实施后它有多透明是通用关系(或通用外键),这可能是一个解决方案。好吧,一旦我理解了这一切。需要更多的咖啡因。

http://www.djangoproject.com/documentation/models/generic_relations/

让我知道您是否解决了这个问题或有任何帮助。谢谢!

让我知道这是否有帮助,或者您有不同的解决方案。

于 2009-02-14T23:26:50.080 回答
0

好的,我通过更多阅读找到了答案……我觉得您想做的正是我所做的,所以就在这里。

我将为此使用 GenericForeignKeys。

首先是进口models.py

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

现在将以下内容添加到您的图像模型中

class Image(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

这让这个模型成为任意数量模型的通用外键。然后将以下内容添加到您想要拥有相关图像的所有模型中

images = generic.GenericRelation(Image)

现在在 admin.py 中,您需要添加以下内容。

from django.contrib.contenttypes.generic import GenericTabularInline

class ImageInline(GenericTabularInline):
    model = Image
    extra = 3
    ct_field_name = 'content_type'
    id_field_name = 'object_id'

然后将其包含在管理员声明中

class ReviewAdmin(admin.ModelAdmin):
    inlines = [ImageInline]

就是这样。它在这里工作得很好。希望这对男人有帮助!。亚当。

于 2009-02-15T02:10:21.480 回答
0

使用两种形式,一种用于房间,一种用于图像:

类图像(模型。模型)

content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
image = models.ImageField(upload_to='')

类 UploadImage(forms.ModelForm):

class Meta:
    model = Image
    fields = ('image')

教室(models.Model):

name = models.CharField(max_length=50)
images = models.ManyToManyField(Image) 

类 RoomForm(forms.ModelForm):

class Meta:
    model = Room

在视图中

如果 request.method == "POST":

    ##2 form, una per l'annuncio ed una per la fotografia
    form = RoomForm(request.POST)
    image_form = UploadImage(request.POST, request.FILES)
    #my_logger.debug('form.is_valid() : ' + str(form.is_valid()))
    if form.is_valid() and image_form.is_valid():
        ##save room
        room = room.save()

        ##save image
        image = image_form.save()

        ##ManyToMany
        room.images = [image]
        room.save()
于 2010-03-08T11:49:47.897 回答