Image from an ImageField ModelForm not uploading into the server

Viewed 28

Hi so I am new to Django and one of the things I'm trying to do is make a simple gallery application. Somehow I can't add images through the server via the forms if I use a Model Form although I can do it using a plain form. I've tried a lot of the stuff in here and also tried some Youtube stuff but it didn't still work.

Here is my models.py

from django.db import models
from django.urls import reverse
from django.core.validators import validate_image_file_extension
from django.core.files.storage import FileSystemStorage


fs = FileSystemStorage(location='/media')
class FavoriteImages(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(favorite=True)


# Create your models here.
class Photo(models.Model):
    name = models.CharField(max_length=120, null=True)
    photo = models.ImageField(storage=fs, upload_to='media/', validators=[validate_image_file_extension])
    date_uploaded = models.DateTimeField(auto_now=True)
    favorite = models.BooleanField(default=False, blank=False)
    slug = models.SlugField(null=True, blank=True)

    gallery = models.Manager()
    gallery_favorites = FavoriteImages()

    class Meta:
        ordering = ['-date_uploaded']

My Views.py

from PIL import Image
def image_new(request, *args, **kwargs):
    Image.init()
    form = PhotoForm(data=request.POST, files=request.FILES)
    if request.method == 'POST':
        form = PhotoForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            redirect('../all')
    context = {
        'form': form
    }
    return render(request, "form.html", context)

My forms.py

class PhotoForm(forms.ModelForm):
    name = forms.CharField(label='',widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Title'}))
    photo = forms.ImageField(widget=forms.FileInput(attrs={'class':'form-control'}))
    favorite = forms.BooleanField(label='Mark as Favorite',widget=forms.CheckboxInput(attrs={'class':'form-check-input'}))

class Meta:
    model = Photo
    fields = ['name',
              'photo',
              'favorite']

my .html

{% extends "base.html" %}

{% block content %}
    {% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post">
        This form is a multipart.
    {% else %}
    <form method="post">
    {% endif %}
        {% csrf_token %}
    {% if form.media %}
    {{ form.media }}
    {% endif %}
    {{ form.as_p }}

    <input type="submit" class="btn btn-primary" value="Save"/>
    </form>

{% endblock %}

I've placed this in the settings:

MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Something I noticed:

  • The media folder (root) remains empty, but Model.photo has an url. (not null)

How do I modify my form so that the image gets posted?

EDIT: I fixed it by changing the widget of the ImageField. I don't know why it works now, but it does. Thanks for all the help

1 Answers

Why all those {% if %} in the template? I think it's unecessary. I would write it as follows,

{% extends "base.html" %}

{% block content %}
    
    <form enctype="multipart/form-data" method="post">
       
    {% csrf_token %}
    
    {{ form.as_p }}

    <button type="submit" class="btn btn-primary" value="Save"></button>
    </form>

{% endblock %}

Your form can also be simplified as such,

class PhotoForm(forms.ModelForm):
    name = forms.CharField(label='',widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Title'}))
    photo = forms.ImageField()
    favorite = forms.BooleanField(label='Mark as Favorite',widget=forms.CheckboxInput(attrs={'class':'form-check-input'}))
'''
You don't need the Meta class when inheriting from forms.ModelForm. I think the widgets aren't necessary, unless you need to style with CSS specifics. 

Your view can also be simplified quite a bit. You don't need PIL Image unless you are modifying your image. 

I would write like this,

def image_new(request, *args, **kwargs):

form = PhotoForm()
if request.method == 'POST':
    form = PhotoForm(request.POST, request.FILES)
    if form.is_valid():
        form.save()
        redirect('../all')
context = {
    'form': form
}
return render(request, "form.html", context)
Django will take care of saving the image to your media folder and assigning it to the ImageField in the model. 
Related