2009-01-22 71 views
3

我有两个模型,RoomImageImage是一个通用的模型,可以钉上任何其他模型。我想在用户发布有关房间的信息时向他们上传图片。我已经编写了可行的代码,但恐怕我已经做到了这一点,特别是以违反DRY的方式。在django的ModelForm中添加一个通用图像字段

希望对django表单更熟悉的人能指出我出错的地方。

更新:

我试图解释,为什么我在评论当前的答案选择了这个设计。总结如下:

我并没有简单地在Room模型上放置ImageField,因为我想要多个与Room模型相关的图像。我选择了一个通用的图像模型,因为我想将图像添加到多个不同的模型。我考虑过的替代方案是在一个Image类中出现多个外键,这看起来很乱,或者是多个Image类,我认为这些类会混淆我的模式。我在第一篇文章中没有说清楚,所以对此感到抱歉。

看到迄今为止没有答案已经解决了如何使这一点更干DRY我想出了我自己的解决方案,即将上传路径添加为图像模型上的类属性,并引用每次这是必要的。

# 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) 
+0

哪里是你的模型代码:

class Meta: model = Room 
的意见

如果request.method == “POST”

? – muhuk 2009-01-22 07:47:44

+0

添加了模型代码 – Prairiedogg 2009-01-22 07:54:43

回答

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() 

而且,我觉得GenericRelation的相反,你应该使用ManyToManyField,在这种情况下,语法添加图像到一个房间会稍微改变。

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() 

看看Basic file uploadsHow do I use image and file fields?

+0

+1:使用工具的功能 – 2009-01-22 11:56:44

+0

我使用了单独的图像类,因为我需要Room模型上的任意数量的图像。为此,我想我至少需要一个带外键的独立模型类。这是通用的,因为我想要在一个以上的模型上任意数量的图像。 – Prairiedogg 2009-01-23 10:35:49

+1

Mira'l! el @DZPM :) – 2012-04-03 14:58:16

0

如何在页面上使用两种表单:一个用于房间,另一个用于图像?

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

0

Django的不支持您的使用情况下,至少在一定程度上:

  • 表单集显示重复形式
  • 模型表单集句柄重复模式形成
  • 在线表单集绑定模型表单集,以实例的相关对象
  • 通用的内嵌表单集做同样的仿制关系

changeset [8279]中引入了通用内嵌窗体集。请参阅the changes to unit tests以了解它们是如何使用的。

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

内联窗体集似乎期望instance=参数中的现有父实例。管理界面可以让你在保存父实例之前填入内联,所以必须有一种方法来实现它。我从来没有尝试过自己。

0

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

这是我的信息 - 希望可以帮助一些人。

模型:图像,审查,制造商,简介

我想回顾,制造商,个人资料中的影像,模型的关系。但是你必须能够为每个对象提供多个图像。 (即一个审查可有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) 

但像你说的。这看起来很sl and,我只是不喜欢它。

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

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

让你得到这个整理或本可以帮助我。谢谢!

让我知道如果这能帮助或者你有不同的解决方案。

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() 

这让这个模型只是说,一个通用外键的任何数量的模型。 然后添加以下到您要在admin.py到有相关图片

images = generic.GenericRelation(Image) 

现在,你需要添加下面的东西所有的车型。

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] 

而且完蛋了。它的工作很棒。希望这有助于男人! .adam。

0

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

类Image(models.Model)

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') 

class Room(models.Model):

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

类RoomForm(forms.ModelForm):

##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() 
相关问题