views:

288

answers:

1

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 %}
A: 

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.

sheats
Thanks so much for the code. I tried it and it worked great. Is it a best practice to set default data in a view like the above example or elsewhere? I'm still flushing out my DRY coding. Thanks!
kfordham281
Not sure if it's the best place to set a default, but as far as DRY goes, as long as you don't repeat that somewhere else it's as good as any since it is only in one place. Consider putting the value in a constant if you find yourself needing to use that value somewhere else.
sheats