0

I have to create a form to make a post with fields like Title, description and images. I could successfully create a post with a single image, but when it comes to multiple images, it is not getting saved. Upon research found that i have to use a separate model and form for images. But i cannot see how is it accomplished in the views. So how do i accomplish this the easy way?

Models.py

class news(models.Model):
    title = models.CharField(max_length=100)
    description= models.TextField(max_length=500) 

class newsimages(models.Model):
    image = models.ImageField(upload_to='/images/')
    related = models.ForeignKey(news,on_delete=models.CASCADE,null=True)
cappedbot
  • 55
  • 6

1 Answers1

0

You can do with inline_formset

create a form

class ImageForm(ModelForm):
    class Meta:
        model = newsimages
        exclude = ()

ImageFormSet = inlineformset_factory(news, newsimage, form=ImageForm, extra=1)

You CreateView would be something like:

class NewsCreate(CreateView):
    model = news
    fields = ['title', 'description']
    success_url = some_url

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['images'] = ImageFormSet(self.request.POST or None)
        return ctx

    def form_valid(self, form):
        ctx = self.get_context_data()
        images = context['images']
        with transaction.atomic():
            self.object = form.save()
            if images .is_valid():
                images.instance = self.object
                images.save()
        return super().form_valid(form)

in news_form.html

<form method="post" enctype="multipart/form-data">
    {{ form.as_p }}
    <table>
        {{images.management_form}}
        {% for f in images.forms %}
            {% if forloop.first %}
                <thead>
                    <tr>
                        {% for field in form.visible_fields %}
                            <th>{{ field.label|capfirst }}</th>
                        {% endfor %}
                    </tr>
                 </thead>
             {% endif %}
              <tr class="{% cycle row1,row2 %} formset_row">
                    {% for field in form.visible_fields %}
                        <td>
                            {# Include the hidden fields in the form #}
                            {% if forloop.first %}
                                {% for hidden in form.hidden_fields %}
                                    {{ hidden }}
                                {% endfor %}
                            {% endif %}
                            {{ field.errors.as_ul }}
                            {{ field }}
                        </td>
                    {% endfor %}
                </tr>
            {% endfor %}
        </table>
        <input type="submit" value="Save"/> 
    </form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'formset/jquery.formset.js' %}"></script>
<script type="text/javascript">
    $('.formset_row').formset({
        addText: 'add image',
        deleteText: 'remove',
        prefix: 'images_set'
    });
</script>

You will need to source jquery.formset.js which I think you'll find in django admin static files.

HenryM
  • 5,557
  • 7
  • 49
  • 105