w5m
w5m

Reputation: 2336

Submitting Django CreateView form to itself

As a newcomer to Django, I'm struggling to achieve my ultimate aim of submitting a form to the same page on which it's defined and displaying values entered in the form within text elements of an SVG diagram, displayed below the form.

Thus far, I've managed to create a form using a CreateView and can submit the contents of that form to a separate view which displays the entered values in SVG format...

models.py

class Diagram(models.Model):
    val1 = models.FloatField(null=True, blank=True, default=None)
    val2 = models.FloatField(null=True, blank=True, default=None)

    def get_absolute_url(self):
        return reverse('diagram-results', kwargs={'diagram_id': self.pk})

forms.py

class DiagramForm(ModelForm):
    class Meta:
        model = Diagram
        fields = ['val1', 'val2']

views.py

def show(request, diagram_id):
    try:
        diagram = Diagram.objects.get(pk=diagram_id)
    except Diagram.DoesNotExist:
        raise Http404("Diagram does not exist")
    return render(request, 'calc_app/diagram.svg', {'diagram': diagram})  

class DiagramCreateView(CreateView):
    model = Diagram
    form_class = DiagramForm

urls.py

urlpatterns = [
    path('diagram/add/', DiagramCreateView.as_view(), name='diagram-add'),
    path('diagram/<int:diagram_id>/', views.show, name='diagram-results'),
]

diagram_form.html

{% extends "calc_app/base_generic.html" %}

{% block content %}
  <form action="." method="post">
    {% csrf_token %}   
    <table>
    {{ form.as_table }}
    </table>
    <input type="submit" value="Submit">
  </form>
{% endblock %}

diagram.svg

<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
  <text id="val1" stroke="#ddd" y="50.0" x="50.0">{{ diagram.val1 }}</text>
  <text id="val2" stroke="#ddd" y="50.0" x="50.0">{{ diagram.val2 }}</text>
</svg>

I'd like to take this one step further and submit the entered form values back to the same page (rather than a separate page/view) and show the results within the SVG diagram. It's straightforward enough to combine the HTML form and SVG diagram into a single template by including the following line immediately below the closing form tag in the diagram_form.html template...

{% include "calc_app/diagram.svg" %}

What I'm struggling to do is post the form contents back to the page it originated from. Can anyone shed any light on how best to do this using the aforementioned building blocks (or more appropriate ones)?

Many thanks in advance.

Upvotes: 0

Views: 270

Answers (2)

JPG
JPG

Reputation: 88589

Initially, update your diagram_form.html file as below, to handle the svg image

{% extends "calc_app/base_generic.html" %}

{% block content %}
    <form action="." method="post">
        {% csrf_token %}
        <table>
            {{ form.as_table }}
        </table>
        <input type="submit" value="Submit">
    </form>
{% endblock %}

<div>
    {% include "calc_app/diagram.svg" %}
</div>

Note that, I have used the include--[Doc] template tag of Django here to re-use the diagram.svg

Then, update the DiagramCreateView class by overriding the form_valid(...) and get_context_data(...) method and also updating the value of template_name attribute

class DiagramCreateView(CreateView):
    model = Diagram
    form_class = DiagramForm
    template_name = "sample/diagram_form.html"

    def form_valid(self, form):
        self.object = form.save()
        return render(
            request=self.request,
            template_name=self.template_name,
            context=self.get_context_data()
        )

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["diagram"] = self.object
        return ctx

In the end, this would result in a below setup, EndResult

Upvotes: 1

Neeraj
Neeraj

Reputation: 783

Modify create view by overriding post method, as following lines of code,

class DiagramCreateView(CreateView):
model = Diagram
form_class = DiagramForm

def post(self, request, *args, **kwargs):
    super().post(request,*args,**kwargs)
    form = DiagramForm(request.POST)
    return render(request,'calc_app/diagram_form.html',{'form':form,'diagram':self.object})

Upvotes: 1

Related Questions