Django - ModelForm: Add a field not belonging to the model

6.6k views Asked by At

Note: Using django-crispy-forms library for my form. If you have a solution to my problem that involves not using the cripsy_forms library, I accept it all the same. Not trying to be picky just need a solution / work around. Thanks

In my form's Meta class I set the model, Driftwood, and it's fields I want to in the form, but I also want to add another field. One that does not belong the the referenced model. This field I want to add is an image. The reason for this field is to build another model from it.

I have a model named Image that has some fields that get populated by doing things with a single models.ImageField(). This Image also has a models.ForeginKey() with a relation to the Driftwood model. So Image can be accessed through an instance of a Driftwood using its relational set property (driftwood.image_set).

In view.py I am using generic.CreateView() as the inherited class that will handle my form class. I plan on using the form_valid() method to acquire through form.cleaned_data, the image that I need. I will then create the image, passing the object.id of my newly instantiated Driftwood and the image into my Image model.

The problem I have though is not knowing how to add a custom field to Django's FormModel that does not belong to the model associated with the form.

forms.py

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit

from . import models

class DriftwoodForm(forms.ModelForm):
    class Meta:
        model = models.Driftwood
        fields = ('user', 'title', 'description')

    def __init__(self, *args, **kwargs):
        super(DriftwoodForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.layout = Layout(
            'user',
            'Insert Image Field Here',
            'title',
            'description',
            ButtonHolder(
                Submit('save', 'Save', css_class='btn-success')
            )
        )

models.py

from base64 import b64decode, b64encode # used to encode/decode image

from django.db import models

class TimeStampMixin(models.Model):
    class Meta:
        abstract = True

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)


class Driftwood(TimeStampMixin):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=255)
    description = models.TextField(max_length=1000)
    slug = models.SlugField(max_length=255)


class Image(TimeStampMixin):

    driftwood = models.ForeignKey(Driftwood)
    image = models.ImageField(upload_to='static/images')

    # gets encoded as a string in the save method
    encoded_image = models.TextField(blank=True, null=False, default='')
2

There are 2 answers

4
HassenPy On BEST ANSWER

This is how you do it to a non django-crispy-forms form:

from django import forms

from . import models


class DriftwoodForm(forms.ModelForm):
    class Meta:
        model = models.Driftwood
        fields = ('user', 'title', 'description', 'image')

    image = forms.ImageField()

full documentation: https://docs.djangoproject.com/en/1.8/ref/forms/fields/#django.forms.ImageField


Now what you have to do is simply use the form as you always do, calling save() on the form won't try to brute save the image to the model specified in the Meta class, but you will be able to do whatever you want with the field.

I'm not sure thou, but i suppose you can do the same with django-crispy-forms, just add the field below and suppose its from the model itself.

0
Brandon Nadeau On

Here's the updated form in case anyone was curious.

class DriftwoodForm(forms.ModelForm):
    class Meta:
        model = models.Driftwood
        fields = ('user', 'title', 'description', 'image')

    image = forms.ImageField()

    def __init__(self, *args, **kwargs):
        super(DriftwoodForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.layout = Layout(
            'user',
            'image',
            'title',
            'description',
            ButtonHolder(
                Submit('save', 'Save', css_class='btn-success')
            )
        )