2

I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?

Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.

models.py:

class Article(models.Model):
    description = models.TextField(_('Description'))

class Image(models.Model):
    article= models.ForeignKey(Article, on_delete=models.CASCADE)
    image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')

forms.py:

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ('description', )

    image = MultiFileField()

    def save(self, commit=True):
        instance = super(ArticleForm, self).save(commit)
        for each in self.cleaned_data['image']:
            Image.objects.create(image=each, article=instance)
        return instance

views.py:

def article_add(request):
    data = dict()
    if request.method == 'POST':
        article_form = ArticleForm(request.POST, request.FILES)
        if article_form.is_valid():
            article = article_form.save(commit=False)
            ******
            article.save()
            data['form_is_valid'] = True
            articles = Article.objects.all
            context = {'articles': articles}
            context.update(csrf(request))
            data['html_article'] = render_to_string('project/article_list.html', context)
        else:
            data['form_is_valid'] = False
    else:
        article_form = ArticleForm()
    context = {'article_form': article_form}
    data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
    return JsonResponse(data)

article_add.html:

{% load widget_tweaks %}

<form method="post" action="{% url 'article_add' %}" class="article-add-form">
    {% csrf_token %}

    {% for field in article_form %}
    <div class="form-group{% if field.errors %} has-danger{% endif %}">
       <label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
       {% render_field field class="form-control" %}
       {% for error in field.errors %}
          <div class="form-control-feedback">{{ error }}</div>
       {% endfor %}
    </div>
    {% endfor %}

    <button type="submit">Submit</button>
</form>
Nurzhan Nogerbek
  • 4,806
  • 16
  • 87
  • 193

1 Answers1

0

Try adding "min_num" constraint on the image field,

image = MultiMediaField(min_num=1, media_type='image')

EDIT

def article_add(request):
    if request.method == 'POST':
        article_form = ArticleForm(request.POST, request.FILES)
        if article_form.is_valid():
            article = article_form.save(commit=False)
            ******
            article.save()
            #assume you have already a view in the name 'article_list'.
            return redirect('article_list')
    else:
        article_form = ArticleForm()
    context = dict(article_form=article_form)
    return render(request, 'project/article_add.html', context)

The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.

Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,

def article_list(request):
    articles = Article.objects.all()
    context = dict(articles=articles)
    return render(request, 'project/article_list.html', context)

Although, these are my personal opinion regarding the code you just shared. Try this approach...

zaidfazil
  • 9,017
  • 2
  • 24
  • 47
  • I have this error: `TypeError: __init__() got an unexpected keyword argument 'media_type'` – Nurzhan Nogerbek May 22 '17 at 05:04
  • Oh, thats for MultiMediaField(), you could try that.... you are only uploading images aren't you? – zaidfazil May 22 '17 at 05:09
  • or MultiImageField() can be used.., which restricts the user to upload images only, using MultiFileField any filetypes can be uploaded... – zaidfazil May 22 '17 at 05:11
  • I tried both `MultiFileField` and `MultiImageField`. I think `save` method which is inside form dont work. I put `print("True")` inside save method just to test. But there was nothing in PyCharm console. Do you think my save method is correct? – Nurzhan Nogerbek May 22 '17 at 05:20
  • does your "image is required" error still persists?? – zaidfazil May 22 '17 at 05:37
  • Yes I still have this message. I am so comfused. – Nurzhan Nogerbek May 22 '17 at 05:44
  • Then ,its not about save method, actually your code never reaches save method.... the files are never passed from validation, I would actually advice you to refactor in your rendering method in template, instead of looping over the fields, try explicitly render the fields like **article_form.description, article_form.image**... – zaidfazil May 22 '17 at 05:50
  • At first I tried to add just `{{ article_form}}`. It raise message under `image` field. Then I tried to add as you said `{{ article_form.description }}` and `{{ article_form.image }}` to template. In that cause I dont have message but after submit, `image` field just became empty. Nothing happens. Submit clears the field. Whats wrong now? – Nurzhan Nogerbek May 22 '17 at 06:03
  • in your views, if form is valid you are rendering **'article_list.html'** and if its not **'article_add.html'**, also, django provides **render** shortcut for directly rendering template... maybe problem would that, I'd update the code shortly – zaidfazil May 22 '17 at 06:08
  • I use ajax to update list of articles ('article_list') after successfull adding new article. So I cant use `return redirect('article_list')`. article_list its just part of the page with must be updated by ajax. I hope you understand what I mean. – Nurzhan Nogerbek May 22 '17 at 06:30
  • Yeah I understand – zaidfazil May 22 '17 at 06:32