Image does not save

Hi,
I tried to create a form that can save images.
All the text input is working and they are saved into the ‘admin’.
But for some reason, the image is not saved.

Here are my codes in app models.py

from django.db import models
from django.contrib.auth.models import User
# Create your models here.

STATUS = (
    (0,"Draft"),
    (1,"Publish")
)

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete= models.CASCADE, related_name='blog_posts')
    updated_on = models.DateTimeField(auto_now= True)
    content = models.TextField()
    image = models.ImageField(null= True, blank=True, upload_to="images/")
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)

    class Meta:
        ordering = ['-created_on']

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        from django.urls import reverse
        return reverse ('blog')

My app forms.py

class PostCreateForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = [
            'title',
            'content',
            'author',
            'status',
            'image',
        ]

        widgets = {

            'title': forms.TextInput(attrs= {'class':'form-control'}),
            'content': forms.Textarea(attrs= {'class':'form-control'}),
            'author': forms.Select(attrs= {'class':'form-control'}),
            'status': forms.Select(attrs= {'class':'form-control'}),
            'image': forms.FileInput(attrs= {'style':'display: none;','class':'form-control', 'required': False,})

        }

my settings.py

# Static files (CSS, JavaScript, Images)

# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'
MEDIA_URL = '/media/'

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

STATICFILES_DIRS = (

    os.path.join(BASE_DIR, 'static'),

)

my app urls.py

from blog import views
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [

    path('', views.PostList.as_view(), name='blog'),
    path('view/<slug:slug>/', views.PostDetail.as_view(), name='post_detail'),
    path('edit/<slug:slug>/', views.PostUpdateView.as_view(), name='post_edit'),
    path('create/', views.PostCreateView.as_view(), name='create'),
    path('delete/<slug:slug>/', views.PostDeleteView.as_view(), name='post_delete'),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

my html file if you need it

<div class="container-fluid pt-5">

    <h2 class="text-center padding text-primary">Create new Article</h2>
    <form method='POST' enctype="multipart/form-data" class="main-form"> {% csrf_token %}
        <div class="row">
            <div class="col">
                {%for field in form%}
                    <div class="form-group">
                        <label class="mylabel">{{ field.label }}</label>
                        {{field}}
                    </div>
                {%endfor%}
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text" id="inputGroupFileAddon01">Upload</span>
                    </div>
                    <div class="custom-file">
                        <input type="file" class="custom-file-input" id="inputGroupFile01" aria-describedby="inputGroupFileAddon01">
                        <label class="custom-file-label"> Upload image {{form.image}}</label>
                    </div>
                </div>                                         
                <input type='submit' value='Post Article' class="btn btn-primary" >                
            </div>
        </div>
    </form>
</div>

Note that all of the forms are working fine except uploading the image.
When clicking, I can still choose file, and it seems the image name is there. But after I clicked save, it is not stored.

Thank you in advance.

Edit: Removed the spacing

Are you doing this through your own view, or are you doing this through the Django admin?

If you’re doing this through your own view, please post your view. If you’re doing this through the Django Admin, please post your ModelAdmin class.

(Note, it would also be really helpful if you could avoid the double-spacing of the lines, it’s making it difficult to read what you’ve posted.)

Ken

1 Like

Ah, I forgot to post my view. It’s in my app view. I’ll post it here.

class PostCreateView(CreateView):
    template_name = 'post_create.html'
    fields = '__all__'

    def get(self, request, *args, **kwargs):
        form = PostCreateForm()
        context = {"form":form}
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        form = PostCreateForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.slug = slugify(post.title)
            form.save()

        context = {"form":form}
        return render(request, self.template_name, context)

I’ll also edit my original post to make it easier for you to read. Thank you.
Note that I can save the image through django admin. But through the view it did not save.

Second paragraph.

2 Likes

Thank you.

Should I put this on my view.py or form.py?

and what does “data” mean in this context?

May I have and example since I cannot understand how to use them. I already tried adding it but getting a lot of errors. Probably I use it in a wrong way.

Thank you so much for your time.

This was the paragraph I was (trying) to refer to:

Secondly, when you use the form, you need to bind the file data. File data is handled separately to normal form data, so when your form contains a FileField and ImageField , you will need to specify a second argument when you bind your form. So if we extend our ContactForm to include an ImageField called mugshot , we need to bind the file data containing the mugshot image:

Which specifically refers to this:

In practice, you will usually specify request.FILES as the source of file data (just like you use request.POST as the source of form data):

# Bound form with an image field, data from the request 
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

or, in the case of the code you’ve provided:

would end up looking like this:

    def post(self, request, *args, **kwargs):
        form = PostCreateForm(request.POST, request.DATA)
        ...
3 Likes

Hi, thank you for your example.

I tried to add request.DATA and this error came out.

When I change it to request.FILES, there are no errors, but the images were still doesn’t save in views.

Yes, I clearly typo-ed on my example, it should be request.FILES.

As to your form, your root problem is that you’re rendering the file input field twice.
If you look at the rendered html in your browser, you’ll see you’ve got two input fields for the file, one hidden, the other displayed. However, they both have the same html element ID which is causing the problem.

This is being caused because you’re iterating through all your form fields in your template - which includes the image field, and then rendering the image field a second time. I believe you need to remove that second field reference - or else not render that field in the upper portion of your template.

3 Likes

It works!
I deleted the input line on HTML and it works fine. Thank you so much for your help.

Thanks a lot! I was facing the same issue and it solved my problem.Glad to have people like you in our community!