Question

I've got a form which includes the option to upload an image. In my model, I've defined a default image name to use when no image is selected for upload. When selecting a file, the form uploads the file to my media directory and properly places the filename in the db field (working as it should). When not selecting a file, that field is left blank in the db. When adding an item to that same db table using Django Admin, the default filename is correctly placed in the db field when no image is selected (and works properly when an image is selected). It's only when using the form and not selecting an image does it not work properly. I've look around for a while but have yet to come up with anything that could help. Any ideas? Any help is much appreciated.

models.py

class Beer(models.Model):
beername = models.CharField(max_length=150)
brewer = models.ForeignKey(Brewery)
style = models.ForeignKey(BeerStyle)
abv = models.DecimalField(max_digits=4, decimal_places=2)
beerdescription = models.TextField()
picture = models.ImageField(upload_to='site_media/pictures/', 
    default='pictures/no_beer_picture.jpg')

def __unicode__(self):
    return self.beername

forms.py

class BeerAddForm(forms.Form):
beername = forms.CharField(
    label=u'Name',
    widget=forms.TextInput(attrs={'size': 75})
)
style = forms.ModelChoiceField(
    BeerStyle.objects.all(),
    label=u'Style',
    widget=forms.Select()
)
abv = forms.DecimalField(
    label=u'ABV',
    widget=forms.TextInput(attrs={'size': 8})
)
beerdescription = forms.CharField(
    label=u'Description',
    widget=forms.Textarea
)
picture = forms.ImageField(
    required=False,
    label=u'Picture',
    widget=forms.FileInput,
    initial='pictures/no_beer_picture.jpg'
)

views.py

def beeradd(request, brewery_id):
brewery = get_object_or_404(Brewery, id=brewery_id)
if request.method == 'POST':
    form = BeerAddForm(request.POST, request.FILES)
    if form.is_valid():
        # Create or get beer
        beer = Beer.objects.create(
            beername = form.cleaned_data['beername'],
            brewer = brewery,
            style = form.cleaned_data['style'],
            abv = form.cleaned_data['abv'],
            beerdescription = form.cleaned_data['beerdescription'],
            picture = form.cleaned_data['picture']
        )
        return HttpResponseRedirect('/beers/')
else:
    form = BeerAddForm()
variables = RequestContext(request, {
    'form': form
})
return render_to_response('beer_add.html', variables)

beer_add.html (the form in question)

{% extends "base.html" %}
{% block title %}Add a Beer{% endblock %}
{% block head %}Add a Beer{% endblock %}
{% block content %}
<form enctype="multipart/form-data" method="post" action=".">
{{ form.as_p }}
    <input type="submit" value="save" />
</form>
{% endblock %}
Was it helpful?

Solution

I would set the default in the view code, after the user submitted the form. So take the initial argument for picture out of the form definition and do something like this in your view:

def beeradd(request, brewery_id):
    brewery = get_object_or_404(Brewery, id=brewery_id)
    if request.method == 'POST':
        form = BeerAddForm(request.POST, request.FILES)
        if form.is_valid():

            # Create or get beer
            pic = form.cleaned_data['picture']
            if not pic:
                pic = 'pictures/no_beer_picture.jpg'

            beer = Beer.objects.create(
                        beername = form.cleaned_data['beername'],
                        brewer = brewery,
                        style = form.cleaned_data['style'],
                        abv = form.cleaned_data['abv'],
                        beerdescription = form.cleaned_data['beerdescription'],
                        picture = pic
                    )
    ...

I think the problem that you are seeing is that the initial may populate the file field with that value, but when the form gets submitted the value 'pictures/no_beer_picture.jpg' is not a valid file on the user's computer so no file is sent with the form. You can verify what is getting sent by printing out form.cleaned_data['picture'] before trying to save the model.

You may want to check to see if you can just assign a string value to the picture attribute on Beer or if you actually need to assign a file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top