私は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)