David Sawyer
David Sawyer

Reputation: 557

Form and File Uploading in Django

I have been trying to figure out what is going wrong when I try to submit a form. I get this response on the web page when I hit submit on the form:

Image:
    This field is required.

It seems to think I have not included an image in the form!

settings.py

...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/path/to/myproject/database/sqlite.db'),
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    }
}
...
MEDIA_ROOT = '/path/to/myproject/media/'
MEDIA_URL = '/media/'
...
INSTALLED_APPS = (
    ...
    'myapp',
)

models.py

from PIL import Image
from django import forms
from django.db import models
from django.forms import ModelForm

UPLOADER_CHOICES = (
    ('C', 'Common User'),
    ('N', 'Nutrition Kitchen'),
)

class Meal(models.Model):

    title       = models.CharField(max_length=100)
    slug        = models.SlugField(unique=True)
    image       = models.ImageField(upload_to='images/')
    serves      = models.IntegerField()
    ingredients = models.CharField(max_length=1000)
    instructions= models.CharField(max_length=1000)
    time_period = models.IntegerField()# in minutes
    uploader    = models.CharField(max_length=1, choices=UPLOADER_CHOICES)

def __unicode__(self):
    return self.title

forms.py

from django import forms
from meal.models import Meal

class MealForm(forms.Form):

    title       = forms.CharField(max_length=100)
    image       = forms.ImageField()
    ingredients = forms.CharField(max_length=1000)
    instructions= forms.CharField(max_length=1000)
    time_period = forms.IntegerField(required=False)
    serves      = forms.IntegerField(required=False)

views.py

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from meal.models import Meal
from meal.forms import MealForm

def upload(request):
    if request.method == 'POST':
        form = MealForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return render_to_response('upload.html', {'form': form})
    else:
        form = MealForm()
    return render_to_response('upload.html', {'form': form}, context_instance=RequestContext(request)
    )

upload.html

{% extends "base.html" %}
{% block content %}
{% if form.errors %}
        <p style="color: red;">
            Please correct the error{{ form.errors|pluralize }} below.
        </p>
{% endif %}
<div data-role="content" style="padding: 15px">
    <form action="" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.errors }}
            {{ form.non_field_errors }}
            {{ form.as_table }}
        <input type="submit" value="Submit" id="Save">
    </form>
</div>
{% endblock %}

Does anyone have any ideas about what I could be doing wrong? I feel like I've tried everything.

Upvotes: 5

Views: 15906

Answers (6)

David Sawyer
David Sawyer

Reputation: 557

Okay, so it turned out that it was an issue with jQuery Mobile, which I didn't mention earlier. All I needed to do was change

<form action="" method="post" enctype="multipart/form-data">

to

<form action="" method="post" enctype="multipart/form-data" data-ajax="false">

because jQuery was trying to handle the POST for me. Apparently when you POST to the same URL in Django and want to handle it manually, you must include the

data-ajax="false"

Upvotes: 7

Andrey Shipilov
Andrey Shipilov

Reputation: 2014

This line:

form.save()

...does nothing. You should be either handling the cleaned_data from the form, or use the ModelForm that has a save() method.

Django Forms | Django ModelForms

Upvotes: 1

mrfunyon
mrfunyon

Reputation: 99

In your model you have

models.ImageField(upload_to='images/')

This field is required. Changing it to

models.ImageField(upload_to='images/', blank=True, null=True)

Will make it not required

Upvotes: 1

Cam
Cam

Reputation: 35

Try using a modelform instead of a regular form.

class MealForm(forms.ModelForm): #Note, this is a Modelform, not a regular old form.
    class Meta: 
        model = Meal

Upvotes: 0

Jonathan
Jonathan

Reputation: 2738

Try this in your forms.py

image = forms.ImageField(widget=forms.FileInput())

I hope it helps

Upvotes: 1

iMom0
iMom0

Reputation: 12931

It seems that you missed this,

class MealForm(forms.Form):
    class Meta:
        model = Meal 
    title = forms.CharField(max_length=100)

Upvotes: 0

Related Questions