title: Adding a generic image field onto a ModelForm in django
body: <p>I have two models, <code>Room</code> and <code>Image</code>.  <code>Image</code> is a generic model that can tack onto any other model.  I want to give users a form to upload an image when they post information about a room.  I've written code that works, but I'm afraid I've done it the hard way, and specifically in a way that violates DRY.</p>
  
  <p>Was hoping someone who's a little more familiar with django forms could point out where I've gone wrong. </p>
  
  <p><strong>Update:</strong></p>
  
  <p>I've tried to clarify why I chose this design in comments to the current answers.  To summarize: </p>
  
  <p>I didn't simply put an <code>ImageField</code> on the <code>Room</code> model because I wanted more than one image associated with the Room model.  I chose a generic Image model because I wanted to add images to several different models.  The alternatives I considered were were multiple foreign keys on a single <code>Image</code> class, which seemed messy, or multiple <code>Image</code> classes, which I thought would clutter my schema.  I didn't make this clear in my first post, so sorry about that.</p>
  
  <p>Seeing as none of the answers so far has addressed how to make this a little more DRY I did come up with my own solution which was to add the upload path as a class attribute on the image model and reference that every time it's needed.</p>
  
  <pre><code># 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)
  </code></pre>