2

I have a many to many field in models-

class A(models.Model):
    file = models.ManyToManyField(B, blank=True)

refering to another class in model

class B(models.Model):
    filename = models.FileField(upload_to='files/')
    user = models.ForeignKey(User)

forms.py

class AForm(forms.ModelForm):
    file = forms.FileField(label='Select a file to upload', widget=forms.ClearableFileInput(attrs={'multiple': True}), required=False)
    class Meta:
        model = A
        fields = '__all__'

How to get the file upload working over here? I had the basic views.py suggested over here- doesn't work https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html

EDITED: views.py

if request.method == 'POST':
    a = A()
    form = AForm(request.POST, request.FILES, instance=a)
    if form.is_valid():
        a=form.save()
        files = request.FILES.getlist('file')
        for f in files:
            a.file.create(filename=f, user=request.user)
        a.file.add(a.id)
        if request.is_ajax():
            return JsonResponse({'success': True})
        return redirect('file_view', a_id=a.id)
     elif request.is_ajax():
        form_html = render_crispy_form(form, context=csrf(request).copy())
        return JsonResponse({'success': False, 'form_html': form_html})

ajax-

$.ajax({
        url: "",
        type: "POST",
        data: formdata,
        contentType: false,
        processData: false,
        success: function(data) {
            if (!(data['success'])) {
                // Replace form data
                $('#{% if not form_id %}form-modal{% else %}{{ form_id }}{% endif %}-body').html(data['form_html']);
                $('#form-submit').prop('disabled', false);
                $('#form-cancel').prop('disabled', false);
                $(window).trigger('init-autocomplete');
            } else {
                alertbox('Form saved', '', 'success');
                $('#form-submit').prop('disabled', false);
                $('#form-cancel').prop('disabled', false);
                setTimeout(function () {
                    location.reload();
                }, 2000);
            }
        },
        error: function (request, status, error) {
            alertbox('AJAX Error:', error, 'danger');
        }
    });
user2715898
  • 921
  • 3
  • 13
  • 20

1 Answers1

1

I'm thinking in something like this:

def your_view(request, a_id):
    a = A.objects.get(id=int(a_id))

    if request.method == "POST" :
        aform = AForm(request.POST, instance=a)

        if aform.is_valid():
            files = request.FILES.getlist('file') #'file' is the name of the form field.

            for f in files:
                a.file.create(filename=f, user=request.user)
                # Here you create a "b" model directly from "a" model

    return HttpResponseRedirect(...)

EDIT: You cannot use instance in AForm if you don't have the model previously created. You are doing a=A(), which is calling __init__ method, but not creating it. Also, I have to say that is kind of weird what you are doing, because you need to create B before A so that you can see B models in A file ManyToManyField.

def your_view(request):

    if request.method == "POST" :
        aform = AForm(request.POST, request.FILES)

        if aform.is_valid():
            a = aform.save() # Here you have the a model already created
            files = request.FILES.getlist('file') #'file' is the name of the form field.

            for f in files:
                a.file.create(filename=f, user=request.user)
                # Here you create a "b" model directly from "a" model

    return HttpResponseRedirect(...)
DavidRguez
  • 1,070
  • 3
  • 12
  • 27
  • Thanks for the reply DavidRguez, it is giving me an error 'No File chosen' still, I have added aform.save() statement additionally to your suggestion. Any pointers? – user2715898 Apr 11 '18 at 15:21
  • I would need to see your template just to have a complete view of what your are doing. Please, see my edits for more information. – DavidRguez Apr 13 '18 at 09:27
  • updated views and template- right now, the form- no matter what i ener or not enter seems to be invalid because its rendering crispy _forms response. Please suggest – user2715898 Apr 13 '18 at 12:43
  • I also uderstand your point doing a=A() but how to approach creation of new model? – user2715898 Apr 13 '18 at 12:45
  • Hi David, what is happening is formdata is empty. I have checked the network tab in chrome developer tools and the request payload section is empty, I am not sure why that is happening :( – user2715898 Apr 16 '18 at 12:56
  • First of all, I don't see where you define `formdata` in your AJAX call. Second, if you are going to use AJAX to submit a form, you need to serialize the formdata. Take a look at this: https://stackoverflow.com/questions/10899384/uploading-both-data-and-files-in-one-form-using-ajax. My answer was focused in using a regular form submission, using HTTP POST request, not AJAX. – DavidRguez Apr 17 '18 at 06:55
  • var formData = new FormData(this); is how I have defined my formData as well. And as on the link- you dont need to serialize formData when using files? – user2715898 Apr 17 '18 at 09:18
  • okay its now working :), changed this to this.parent().parent() and evverything looks fine if I am editing the form- an already created model but if I create a new model- it is throwing a 505 error, I think this has something to do with your suggestion of b model not being already there, not sure how to solve it though :( – user2715898 Apr 17 '18 at 15:15