2009-01-22 65 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() 
相關問題