3

私は2つのモデルを持っていRoomますImage. Image他のモデルに追加できる汎用モデルです。部屋に関する情報を投稿するときに、画像をアップロードするためのフォームをユーザーに提供したいと考えています。私は機能するコードを書きましたが、難しい方法で、特に DRY に違反する方法でそれを行ったのではないかと心配しています。

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

また、GenericRelationの代わりにManyToManyFieldを使用する必要があると思います。この場合、部屋に画像を追加するための構文が少し変更されます。

于 2009-01-22T12:12:45.270 に答える
0

Djangoは、少なくともある程度まではユースケースをサポートします。

  • フォームセットは繰り返しフォームを表示します
  • モデルフォームセットは、繰り返されるモデルフォームを処理します
  • インラインフォームセットは、モデルフォームセットをインスタンスの関連オブジェクトにバインドします
  • 一般的なインラインフォームセットは、一般的な関係に対しても同じことを行います

汎用インラインフォームセットがチェンジセット[8279]に導入されました。単体テストの変更を参照して、それらがどのように使用されるかを確認してください。

一般的なインラインフォームセットを使用すると、フォーム内の既存の部屋の複数の保存済み画像を表示することもできます。

インラインフォームセットは、instance=引数に既存の親インスタンスを期待しているようです。管理インターフェースでは、親インスタンスを保存する前にインラインで入力できるため、それを実現する方法が必要です。私はそれを自分で試したことがありません。

于 2009-02-10T08:38:50.193 に答える
0

私はこのページがこの同じ問題の解決策を探しているのを見つけました。

ここに私の情報があります-うまくいけばいくつかを助けます。

モデル:画像、レビュー、メーカー、プロフィール

レビュー、メーカー、プロファイルに画像モデルとの関係を持たせたいです。ただし、オブジェクトごとに複数の画像を用意できる必要があります。(つまり、1つのレビューに5つの画像を含めることができ、別のレビューに3つの画像を含めることができます)

もともと私は

images = ManyToManyField(Image)

他の各モデルで。これは問題なく動作しますが、管理者(コンボ選択ボックス)には問題があります。しかし、これはあなたにとっての解決策かもしれません。私がやろうとしていることのためにそれが好きではありません。

私が現在取り組んでいるもう1つのことは、複数の外部キーを持つことです。

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)

しかし、あなたが言ったように。これはかなりずさんな見た目で、私はそれが好きではありません。

私が見つけたもう1つのことは、脳が完全に包まれていないことです(そして、実装後の透明性がどれほど透明であるかは、解決策になる可能性があります。一般的な関係(または一般的な外部キー)です。すべてを理解したら、必要です。より多くのカフェイン。

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

Image Model に以下を追加します。

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

部屋用と画像用の 2 つのフォームをページに使用するのはどうでしょうか。

画像フォームの一般的な外部キー フィールドを不要にし、ルームを保存した後にビューに値を入力するだけです。

于 2009-02-10T08:28:03.543 に答える
0

部屋用と画像用の 2 つのフォームを使用します。

クラス画像(モデル.モデル)

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 に答える