"Capturing" data from a Django slider

Viewed 84

This question has “grown” from Django Model Field for html5 Range Slider but is specific and different enough to warrant its own question, I believe, rather than continue in the comments section.

The aim of the original post was to write Django code that would render and display a slider in the webpage. That has been done. The challenge that this question relates to is writing the value of the slider to a field in a table/model. I will first show code for a table/model update that works then show how far I have got displaying the slider and showing where I am stuck. I am giving all this detail rather than just asking for a fix, because I am trying to understand how the Django code works - and by trying to explain it hopefully you can correct my misunderstandings.

First I will show the code I have copied and modified that just displays textboxes that the View(?) form(?) takes the input values and write a new record to the table. I will describe my understanding of the various parts of the view and the form.

Then I will show the code I have to display the slider and how it differs from the working code – which is where I need help to write data to the table/model.

My template, create.html, that works contains:

<form method="POST">
            {% csrf_token %}
                <div class="panel-body">
                    <div class="row">
                        <div class="col-lg-12">
                            <div class="form-group">
                                <label for="question">Enter Survey Question</label>
                                {% render_field form.q_text rows="3" class="form-control" %}
                            </div>
                        </div>
                    </div>

                    <div class="row">
                        <div class="col-lg-5">
                            <div class="form-group">
                                <label for="Choice1_text ">Choice 1</label>
                                {% render_field form.Choice1_text class="form-control" %}
                                <label for="C1_type">Type 1</label>
                                {% render_field form.C1_Type class="form-control" %}

                            </div>
                        </div>
                        <div class="col-lg-5">
                            <div class="form-group">
                                <label for="option2">Choice 2</label>
                                {% render_field form.Choice2_text  class="form-control" %}
                                <label for="C2_type">Type 2</label>
                                {% render_field form.C2_Type class="form-control" %}
                            </div>
                        </div>
                       
                    </div>

                    <div class="row">
                        <hr />
                        <div class="col-lg-4">
                            <button type="submit" class="btn btn-info">Submit</button>
                        </div>
                    </div>
                </div>
            </form>

My understanding the form will be “interpreted” by the view as a POST.

The input fields which appear on the rendered webpage as input boxes, are coded in the template as in the following examples:

<label for="question">Enter Survey Question</label>
<label for="Choice1_text ">Choice 1</label>
<label for="C1_type">Type 1</label>

(There are other inputs)

Are “passed back” to the View(?) form(?) via the {% render_field

{% render_field form.q_text rows="3" class="form-control" %}
{% render_field form.Choice1_text class="form-control" %}
{% render_field form.C1_Type class="form-control" %}

There are other {% render_field

The

form.q_text 
form.Choice1_text
form.C1_Type

are the names of the fields in the table/model to be updated by the data typed in the boxes on the webpage.

in forms.py, there is:

from django import forms
… deleted lines …
class AnyForm(forms.ModelForm):
    class Meta:

        model = CC_Questions
        fields = ['q_text', 'Choice1_text', 'Choice2_text','C1_Type','C2_Type']

where:

class AnyForm(forms.ModelForm):

indicates this is a “modelForm” which is “used unmodified” in a view(?) template(?) will result in a collection of boxes to accept input being displayed on the screen, without any formatting. the:

model = CC_Questions

is the name of the model/table to which data will be written the:

fields = ['q_text', 'Choice1_text', 'Choice2_text','C1_Type','C2_Type']

Are the fields that will display input boxes in the template and will be the fields where the data is written in the model when data is input in the webpage. This form may not display all of the fields in the model if they do not all require a value from this form.

The view is:

def p2create(request):
    if request.method == 'POST':
        
        form = AnyForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('/polls/p2')

    else:
        
        form = AnyForm()
    context = {'form' : form}
    return render(request, 'pollapp2/create.html', context)

Since the template contained the line

<form method="POST">

the code below

if request.method == 'POST':

will evaluate as True resulting in the form, AnyForm, being "used"

form = AnyForm(request.POST)

if the form is valid (how can a form be “invalid??)

if form.is_valid():

then save the values that the template “passes back” to the form (??) via the

{% render_field form.<field name>

The form “passes back” values to the view (??) via the

model =<model name>
fields = [“<field1>”, “<field2>”, ….]

and the view writes to the model (??) via the

form.save()

The next web page to be displayed is

return redirect('/polls/p2')

So that is my best understanding of how working code writes data to a table.

Now follows is the code I have working to display a slider, and the slider value, when I press the “Try it” button. The code successfully displays the value corresponding to the position of the slider on the underlying range. However, from the following I can’t work out what code I need to modify to “trap” the value of “myint” and write it to the appropriate field in a new record in the model.

Template that displays the slider:

<!-- p2slider.html -->
{% extends "pollapp2/base.html" %}
<!-- load widget tools to give me more control over layout of form in template -->
{% load widget_tweaks %}
{% block title %}P2Slider test{% endblock %}

{% block main %}
<div class="row">
    <div class="col-lg-8 col-lg-offset-2">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">P2Slider test</h3>
            </div>

            <div class="panel-body">

                {% render_field form.RangeInput class="SliderForm" %}
                {{form.myint}}
                <label for="myint">Input Value</label>
                <!-- https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_range_value2 -->
                <p>Click the button to display the value of the value attribute of the slider control.</p>
                <button onclick="myFunction()">Try it</button>
                <p id="slider_val"></p>

                <script>
                    function myFunction() {
                        var x = document.getElementById("id_myint").value;
                        document.getElementById("slider_val").innerHTML = x;
                    }
                </script>
                <!-- end -->
            </div>
            <div class="panel-footer">
                Data here
            </div>

        </div>
    </div>
</div>
{% endblock %}

Form that “relates” to this template. I notice that this code doesn’t use ModelForm

# attempt at range input slider
#
from polls.widgets import RangeInput
# 
class SliderForm(forms.Form):
    myint = forms.IntegerField(widget=RangeInput)

View I have copied and modified from the view for “Create” but I guess is wrong because I don’t have a model form:

def p2slider(request):
    if request.method == 'POST':
        form = SliderForm(request.POST)
        if form.is_valid():
            form.save() # ??????
            context = {'form' : form} # ????
            return render(request,'pollapp2/p2slider.html',context)
    else:
        form = SliderForm()
    context = {'form' : form} # ??????
    return render(request,'pollapp2/p2slider.html', context)

So I’m guessing I need to change the view function p2slider to the relevant model, cc_resp_nofk. But I don’t know what to code.

1 Answers

This is a simple Form, so there is no .save() method (since it is unclear what that would mean). You can obtain the value with the form.cleaned_data:

def p2slider(request):
    if request.method == 'POST':
        form = SliderForm(request.POST)
        if form.is_valid():
            slider_value = form.cleaned_data['myint']
            # do something …
    else:
        form = SliderForm()
    context = {'form' : form}
    return render(request,'pollapp2/p2slider.html', context)

or if you want to use it in a ModelForm, you can plug this in as the widget of a form field:

class SomeModelForm(forms.ModelForm):
    class Meta:
        model = SomeModel
        fields = ['intfield']
        widgets = {
            'intfield': RangeInput
        }

If SomeModel thus has an intfield as field, you can use the RangeInput as widget for that field, and then .save() that form.

Related