Best way to update multiple templates based on form submission?

Hello,

I’m working on a project where users can provide different numerical values in my template named variables_input then after submitting the values calculations are run using these values and the results are stored in different models. Depending on which page the user selects after the calculation, there are different corresponding class based views that retrieves the data from the different models so it can be displayed on a specific page. All of this works fine, but I am now trying to create a new form in my variables_input template (and the same corresponding class based view) where the user can retrieve the values used in prior runs, and this works on the variables_input template resulting with the values being displayed on the page. However when the user goes to another page the values displayed are the most recently run calculations. How do I make it so when the user chooses a past run that they don’t have to run the calculations but just get the values from the appropriate models to be displayed on the appropriate page? I think the issue could be solved by changing by BasicTableView (shown below) class get method possibly but I would still need it to work when the calculations are run? I was wondering if signals could achieve the desired result or if a simpler solution is possible. Below is an example of my project’s code.

variables_input.html

{% block content %}
<form action="" method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" , value="Submit" name="prior_run">
</form>

<form action="" method="post">
  <h2>Variables Table One</h2>

  {% csrf_token %}
  <!-- Table Columns -->
  <table>
    <table class="vartable" style="text-align: center;">
      <colgroup>
        <col class="grey">
      </colgroup>
      <thead>
        <tr>
          <th>Variable 1</th>
          <th>Variable 2</th>
          <th>Variable 3</th>
          <th>Variable 4</th>
          <th>Run Name</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <div>
            <td><input type="text" value="{{inputs_list.0}}" name="var_one"></td>
            <td><input type="text" value="{{inputs_list.1}}" name="var_two"></td>
            <td><input type="text" value="{{inputs_list.2}}" name="var_three"></td>
            <td><input type="text" value="{{inputs_list.3}}" name="var_four"></td>
            <td><input id="run_name" type="text" value="{{inputs_list.5}}" name="run_name"></td>
          </div>
        </tr>
        <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
        </tr>
      </tbody>
    </table>
  </table>
  <input type="submit" , value="Submit">
</form>

forms.py

class InputsForm(forms.Form):
    past_run_names = [
        (i["run_name"], i["run_name"])
        for i in InputVariables.objects.values("run_name")
    ]
    run_name = forms.ChoiceField(choices=past_run_names)

views.py

class VariableInputView(FormView, View, LoginRequiredMixin):
    template_name = "variable_input.html"
    input_model = InputVariables
    inputs_form_class = InputsForm

    def get(self, request):
       # perform get method

    def post(self, request):
        post_data = request.POST.dict()
            if "prior_run" in request.POST:
                form = self.inputs_form_class(request.POST)
                if form.is_valid():
                   inputs_query = self.input_model.objects.filter(
                       run_name=run_name
                   ).values_list(*first_assumptions_list)
                   inputs_list = list(inputs_query[0])
                   return HttpResponseRedirect(self.request.path_info)
                return render(
                    request,
                    self.template_name,
                    {
                        "inputs_list": inputs_list,
                        "form": form,
                    },
                )
            else:
                 # run the calculation

class BasicTableView(View, LoginRequiredMixin):
    model = None
    template_name = None

    def get(self, request):
        """
        Get the latest entry in the database when the last time the table was
        generated.
        """
        if not request.user.is_authenticated:
            return redirect("/accounts/login")
        else:
                input_var_query = InputVariables.objects.values_list(
                    "var_one",
                    "var_two",
                    "var_three",
                    "var_four",
                    "run_name",
                ).latest("time_stamp")
                input_var_list = list(input_var_query)
                data = (
                    self.model.objects.filter(
                        input_variables__var_one=input_var_list[0],
                        input_variables__var_two=input_var_list[1],
                        input_variables__var_three=input_var_list[2],
                        input_variables__var_four=input_var_list[3],
                        input_variables__run_name=input_var_list[4],
                    )
                    .order_by("time_stamp")
                    .reverse()[: self.end_slice : -1]
                )
                print(data)
            except InputVariables.DoesNotExist:
                ...

            return render(
                request,
                self.template_name,
                {"data": data, "input_var_list": input_var_list},
            )
     

class SummaryOfResultsView(BasicTableView):
    model = SummaryOfResults
    template_name = "summary_of_results.html"

models.py

class SummaryOfResults(models.Model):
    result_one = models.TextField()
    result_two = models.TextField()
    result_three = models.TextField()
    input_variables = models.ForeignKey(InputVariables, on_delete=models.CASCADE)
    time_stamp = models.DateTimeField(auto_now_add=True, blank=True)

class InputVariables(models.Model):
    var_one = models.TextField()
    var_two = models.TextField()
    var_three = models.TextField()
    var_four = models.TextField()
    run_name = models.TextField()
    time_stamp = models.DateTimeField(auto_now=True, null=True)

    def __str__(self):
          # return strings

results.html

{% block content %}
<div class="container">
    <div class="row">

        <!-- Table Columns -->
        <div class="col-md-8 mt-4 left">
            <style>
                .grey {
                    background-color: #dfdede;
                }

                .firsttable th:nth-child(1),
                .firsttable th:nth-child(2),
                .firsttable th:nth-child(3),
                .firsttable tr:last-child td {
                    background-color: #dfdede;
                }
            </style>
            <table class="firsttable" style="text-align: center;" border="1">
                <colgroup>
                    <col class="grey">
                </colgroup>

                <thead>
                    <tr style="font-size: small">
                        <th>Result One</th>
                        <th>Result Two</th>
                        <th>Result Three</th>
                    </tr>
                </thead>

                <tbody>
                    {% for d in data %}
                    <tr style="font-size: small">
                        <td>{{d.result_one}}</td>
                        <td>{{d.result_two}}</td>
                        <td>{{d.result_three}}</td>
                    </tr>
                    {% empty %}
                    <tr>
                        <td colspan="5">Currently no Data Available</td>
                    </tr>
                    {% endfor %}
                </tbody>

            </table>

        </div>
        {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
        <div class="col-md-8 mt-3 left">
            <style>
                .grey {
                    background-color: #dfdede;
                }

                .CurrentVariableTable th:nth-child(1),
                .CurrentVariableTable th:nth-child(2),
                .CurrentVariableTable th:nth-child(3),
                .CurrentVariableTable th:nth-child(4),
                .CurrentVariableTable th:nth-child(5) {
                    background-color: #dfdede;
                }
            </style>
            <table class="CurrentVariableTable" style="text-align: center;" border="1">
                <thead>
                    <tr style="font-size: small">
                        <th>Variable One</th>
                        <th>Variable Two</th>
                        <th>Variable Three</th>
                        <th>Variable Four</th>
                    </tr>
                </thead>
                <tbody>
                    <tr style="font-size: small">
                        <td>{{input_var_list.0}}%</td>
                        <td>{{input_var_list.1}}%</td>
                        <td>{{input_var_list.2}}%</td>
                        <td>{{input_var_list.3}}%</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}

I tried to make the example code as basic as possible. Please let me know if you see any issues or have any questions about it. Thanks!

How much experience do you have with Django? (Or in web development in general?)

Don’t confuse information about updating data in the database with what’s displayed on a web page.

Data doesn’t exist in “pages”. Data exists in the database.

The Django views reads the data from the database and creates pages using that data. The data being used to create pages can come from any number of tables. There is no direct correspondence between pages and tables.

There’s no need to involve signals in any of this. This is a straight-forward application that doesn’t require anything out-of-the-ordinary.

Point taken. I was lazy in my framing of my question and did not use the proper terminology. I will update my question to provide more context about the problem I am trying to solve.

Ok, let me try to break this down to make sure I understand the situation.

I think the basic question you’re asking is that you have a page where a person can make a selection.

When they submit the form containing the selection, you want to use that selection in the view to determine what data is retrieved.

Is this an accurate summary of your question?

If so, and based upon your VariableInputView.post method, I can see where you’re using prior_run to retrieve some data (inputs_list) - but instead of rendering that data, you’re redirecting back to yourself and throwing away the data you retrieved. I’m guessing that what you really want to do is to render that data.

Am I on the right track here?

Also, a couple other points:

  • Do not think about your logic and data flows in terms of “pages” and “templates”. Focus on the views being used. A template is just data - it doesn’t “do” anything. Your mindset should be on what views are being executed and the data that is being passed to them.

  • Do not try to dynamically define choices as a class variable in a form. This is not going to do what you think it does:

This will run once, when that forms.py file is imported. It does not get run every time you create an instance of the form. See the docs at ChoiceField.choices and the docs it references at Field.choices.

  • Mixins should appear before the base classes in class definitions. Also, since FormView inherits from View, there is no need to show both in your VariableInputView definition.

Yes, that is exactly what I am trying to do with the prior_run form.

Yes that is what I am trying to do but I would also like the retrieved data to also show in the variable_inputs.html which is why I was just redirecting back to that page. Is this generally a bad idea?

  • Thank you, I will immediately review the docs at ChoiceField.choices and the docs it references at Field.choices.
  • I will change my code so that the Mixins appear before the base classes in all my class definitions where relevant.

Yes, because when you issue a redirect, you’re causing the browser to issue a new request. This new request isn’t going to have the data that you retrieved.

Rather than redirecting, just render the data as if you had issued the request.