Search code examples
pythonajaxdjangoimageinline-formset

How to POST Django Inline Formset with images via AJAX


I'm trying to process inline formset with images via Ajax:

forms.py

class UserDogCreateForm(forms.ModelForm):
    class Meta:
        model = UserDog
        fields = ['name', 'breed', 'gender']


class UserDogImageCreateForm(forms.ModelForm):
    class Meta:
        model = UserDogImage
        fields = ['image', 'dog']
        labels = {'image': ''}


UserDogCreateFormSet = forms.inlineformset_factory(
    UserDog,
    UserDogImage,
    form=UserDogImageCreateForm,
    extra=3,
    can_delete=False,
    can_order=False,
)

views.py

class UserDogCreateView(LoginRequiredMixin, CreateView):
    model = UserDog
    form_class = UserDogCreateForm

    def get_context_data(self, **kwargs):
        context = super(UserDogCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            context['dog_image_inlines'] = UserDogCreateFormSet(self.request.POST, self.request.FILES)
        else:
            context['dog_image_inlines'] = UserDogCreateFormSet()
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        inlines = context['dog_image_inlines']
        with transaction.atomic():
            if inlines.is_valid():
                form.instance.user = self.request.user
                self.object = form.save()
                inlines.instance = self.object
                inlines.save()
                user_dogs = UserDog.objects.filter(user=self.request.user)
                return JsonResponse({'form_is_valid': True, 'user_dogs': serializers.serialize('json', user_dogs)})
            else:
                return JsonResponse({'form_is_valid': False})

    def form_invalid(self, form):
        return JsonResponse({'form_is_valid': False})

.html

<form id="dog-create-form" enctype="multipart/form-data" action="{% url 'dog-create' %}" method="post">
    {% csrf_token %}
    {{ form }}
    {{ dog_image_inlines.as_p }}
    <button type="submit">Submit</button>
</form>

.js

var dogCreateForm = $('#dog-create-form');
dogCreateForm.submit(function(e){
    e.preventDefault();
    var data = new dogCreateForm.serialize();
    console.log(data);
    $.ajax({
        url: '/accounts/dog-create/',
        type: 'post',
        dataType: 'json',
        data: data,
        success: function(data) {
            if (data.form_is_valid) {
                console.log('Dog created!');  // <-- This is just a placeholder for now
            } else {
                console.log('Dog not created!')
            }
        },
    });
})

After submit UserDog data saves, but no images saves in UserDogImage and it seems like everything is ok with forms.py and views.py.

I tried as well

var data = new FormData(dogCreateForm);

but it gives 403, cause it doesn't see csrftokenmiddleware inside FormData for some reason


Solution

  • If you seeking the same problem just use FormData like that:

    .js

    var dogCreateForm = $('#dog-create-form');
    dogCreateForm.submit(function(e){
        e.preventDefault();
        var data = new FormData(this);
        $.ajax({
            url: '/accounts/dog-create/',
            type: 'post',
            dataType: 'json',
            data: data,
            processData: false,
            contentType: false,
            success: function(data) {
                if (data.form_is_valid) {
                    console.log('Dog created!');  // <-- This is just a placeholder for now for testing
                } else {
                    console.log('Dog not created!')
                }
            },
        });
    })