"Capturing" data from a Django slider - python-3.x

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.

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

Django view function isnt working correctly

so the basic goal of my project is to allow teachers and admin to login to the system and take attendance for the students. my new issue is that i have a view function that is suppose to check to see if students student is already added to the respective class and if they are it will exclude them from the drop down menu and display the students who aren't in the class but it not doing that instead it is showing me a blank drop down menu. the way i have it set up is that the admin clicks the add student button then it will convert a .html page to modal which brings up the list of students to select from. When i add the form responsible for saving the student to the class in the Django admin it work perfect but i cant seem to get it to work in the user section Ui. I am new to Django and this is my first project so any help is really appreciated
Views
#check to see if students already exist in class and display those who aint to be added
#login_required
def manage_class_student(request, classPK=None):
if classPK is None:
messages.warning(request,'Class ID is Unknown')
else:
context['classPK'] = classPK
_class = Room.objects.get(id=classPK)
# print(ClassStudent.objects.filter(classIns = _class))
students = Student.objects.exclude(id__in=ClassStudent.objects.filter(classIns=_class).values_list('student').distinct()).all()
context['students'] = students
return render(request, 'manage_class_student.html', context)
#save the students to the respective class after being selected
#login_required
def save_class_student(request):
form = SaveClassStudent()
if request.method == 'POST':
form = SaveClassStudent(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Student has been added successfully.")
redirect('class_detail')
else:
messages.error(request, 'Error Adding student in class')
template with the form to show the available students
<!-- Modal -->
<div class="modal fade" {% block modal-id %} id="addModal{{class.pk}}" {% endblock%} data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="addModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title" id="addModalLabel"> {% block modal-title%}<i class="fas fa-plus"></i> Add
Student To Class{% endblock%}</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="container-fluid">
<form {% block action %} action="{% url 'save-class-student' %}" {% endblock%} method="post">
{% csrf_token %}
<div class="modal-body">
<input type="hidden" name="classIns" value="{{ classPK }}">
<div class="form-group mb-3">
<label for="student" class="control-label">Student</label>
<select name="student" id="student" class="form-select rounded-0 select2" required>
<option disabled selected></option>
{% for student in students %}
<option value="{{ student.id }}">{{ student }}</option>
{% endfor %}
</select>
</div>
<div>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
What triggers the modal
<div class="tools">
<button type="button" class="btn btn-secondary border rounded-0 bg-gradient btn-sm"
id='print_attendance_report'><i class="fa fa-print"></i> Print Attendance Report</button>
<a data-bs-toggle="modal" data-bs-target="#addModal{{class.pk}}"> <button type="button"
class="btn btn-primary rounded-0 bg-gradient btn-sm" id='add_new'><i class="fa fa-plus"></i>
Add Student</button></a>
</div>
form that save students to classroom
class SaveClassStudent(forms.ModelForm):
classIns = forms.IntegerField()
student = forms.IntegerField()
class Meta:
model = ClassStudent
fields = ('classIns', 'student')
def clean_classIns(self):
cid = self.cleaned_data['classIns']
try:
classIns = Room.objects.get(id=cid)
return classIns
except:
raise forms.ValidationError("Class ID is Invalid.")
def clean_student(self):
student_id = self.cleaned_data['student']
_class = Room.objects.get(id=self.data.get('classIns'))
student = Student.objects.get(id=student_id)
try:
cs = ClassStudent.objects.get(classIns=_class, student=student)
if len(cs) > 0:
raise forms.ValidationError(
f"Student already exists in the Class List.")
except:
return student

Show image name inside the image field in Django forms

I have this edit or update form in which I want to display only the image name in the form for a better user experience so that the user could know which image he has uploaded while creating the data.
I am storing the image name in the model as well,but i want to display the image name inside the image field.
forms.py
class MenuCategoryForm(forms.ModelForm):
image = forms.ImageField(allow_empty_file=True, required=False)
class Meta:
model = MenuCategory
fields = ['name', 'description', 'menu_options']
view
def menu_category_update(request, id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid():
if request.FILES['image']:
image = request.FILES['image']
image_url = upload_image(image, 'menu_category', image.name)
obj = form.save(commit=False)
obj.image_url = image_url
form.save()
else:
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(instance=item)
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
Template
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %} {{ form|crispy }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
Well in other to get the name of the image in your form you will be better off in using a form initial like so:
def menu_category_update(request,id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid:
obj = form.save(commit=False)
# obj.username = request.user
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(
initial={'image':item.image,
'name':item.name,
'description':iteem.description,
})# this are the fields that we want to show in the form
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
In your form html you will apply the form initial to the field that you want to show in your form, by doing something like this: form.initial.name As i have illustrated below :
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %}
<label> Image name </label>
{{form.initial.name}}
<label> Description </label>
{{ form.initial.description }}
<label> Image </label>
{{ form.initial.image }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

Showing model data as dropdown list in html Template in Django?

I am trying to access model's data for implementation as dropdown menu but I got stuck in this problem. Can anyone help me??
Here is what i have....
views.py
def educationdata(request):
obj = DegreeDetails.objects.all()
context={
'Data':obj
}
return render(request,'Education.html', context)
This the view I have created for the model DegreeDetails
Model.py
class DegreeDetails (models.Model):
degree = models.CharField(max_length=10)
discipline = models.CharField(max_length= 15)
def __str__(self):
return '%s %s'%(self.degree, self.discipline)
This is the model i am using and this model is used as a ForeignKey in another model as follows, hence i want to show it as dropdown field
degree_details = models.ForeignKey(DegreeDetails, on_delete= models.CASCADE)
Template.Html
<div class="col-lg-8 col-md-8">
<label>Degree Details</label>
<input type="text" name="degree_details" id="inputdegree_details" class="form-control" placeholder="Select from Dropdown" value="{{education_form.initial.degree_details}}">
<select class="form-control">
{% for data in Data %}
<option>{{data}}</option>
{% endfor %}
</select>
Look forward to your responses, Thank you
You should use django forms. It is well explained in the docs.
It is better to use Django Forms or modelforms.
Official Document https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/
for fixing the current code that you have written.
you need to set id as a value for each option in the dropdown.
<div class="col-lg-8 col-md-8">
<label>Degree Details</label>
<input type="text" name="degree_details" id="inputdegree_details" class="form-control" placeholder="Select from Dropdown" value="{{education_form.initial.degree_details}}">
<select class="form-control">
{% for data in Data %}
<option value="{{data.id}}">{{data}}</option>
{% endfor %}
</select>

Exception Value: Cannot use None as a query value Django Framework

Help required, please.
I'm doing a level 6 Diploma in Software Development. Right now I'm doing a project that requires a gym app to be built.
We've decided on using Python/Django as our language/framework.
I have my models, urls, views, and templates working thus far. (Videos display and its own page)
However, I need to implement a search bar to search both video content and text context within the app.
I have the video model set up in /admin. migrations are done.
Do I need another model to search for normal content in my app?
The search bar is in my base.html template.
I want to use the search bar to do a query and pass the results onto a results template page
which extends base.html.
The error I get is the below;
Exception Type: ValueError
Exception Value: Cannot use None as a query value
Can someone point me in the right direction? photos of code attached.
base.html
<!-- Navbar Right Side -->
<div class="navbar-nav">
<form class="form-inline my-1 my-lg-0" action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Search" aria-label="Search">
<a class="btn btn-secondary my-2 my-sm-0" href='/gymapp/videos/' type=submit>Search</a>
</form>
<a class="nav-item nav-link" href="#">Login</a>
<a class="nav-item nav-link" href="/register">Register</a>
</div>
search_results.html
{% extends "gymapp/base.html" %}
{% load embed_video_tags %}
{% block content %}
{% for i in obj %}
{% video i.video 'tiny' %}
<ul class="list-unstyled mt-3 mb-4">
<li>Name: {{ i.video_name }}</li>
<li>Description: {{ i.content }}</li>
</ul>
{% endfor %}
{% endblock content %}
urls.py
path('videos/', VideoResultsView.as_view(), name='search_results'),
models.py
from django.db import models
from embed_video.fields import EmbedVideoField
class Video(models.Model):
category = models.CharField(max_length=200)
video_name = models.CharField(max_length=200)
content = models.CharField(max_length=500)
video = EmbedVideoField() # same like models.URLField()
stats = models.CharField(max_length=20)
class Meta:
verbose_name_plural = 'videos'
def __str__(self):
return self.category
views.py
class VideoResultsView(ListView):
model = Video
template_name = 'search_results.html'
def get_queryset(self):
query = self.request.GET.get('q')
video_list = Video.objects.filter(
Q(category__icontains=query) | Q(video_name__icontains=query)
)
return video_list
Hoping someone can point me in the right direction. Error Description
Found my answer.
<form class="form-inline my-1 my-lg-0" action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Search" aria-label="Search">
<a class="btn btn-secondary my-2 my-sm-0" href='/gymapp/videos/' type=submit>Search</a>
</form>
I shouldn't have used an tag for the button. Changed it to tag and now the query is working.
silly mistake.

How can I read user inputs from a dynamically created form in flask?

I want to create a dynamic input form and read the user inputs back when a button ("Submit") is pressed, what is the best way (a good way) to do this?
I have tried creating a dynamic form with a FieldList but I was unable to get the values from the user.
This is (hopefully all of) the relevant code:
forms.py
class EntryForm(Form):
field = StringField()
class DynamicForm(FlaskForm):
parameter = FieldList(FormField(EntryForm), min_entries=1)
submit = SubmitField('Submit')
routes.py
#app.route("/new", method=['GET', 'POST'])
def new_form():
form = DynamicForm()
if form.validate_on_submit():
values = form.parameter #This does not work as intended.
do_stuff(values)
return redirect(url_for('index'))
parameter = utils.get_parameter()
return render_template('dynamic_form.html', form=form, parameter=parameter)
where utils.get_parameter() returns an unknown list of parameters. Or to be precise the function expects a parameter and returns a list based on this paramater, but I have omitted this here.
dynamic_form.html
{% extends "layout.html" %}
{% macro render_field(item) %}
<div class="form-group">
<label class="form-control-label">{{ item.label }}</label>
<input type="text" name="{{ item.name }}" class="form-control" value="{{ item.value }}"/>
</div>
{% endmacro %}
{% block content %}
<div class="content-section">
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset class ="form-group">
<legend class="border-bottom mb-4">Parameter</legend>
{% for item in form.parameter %}
{{ render_field(item) }}}
{% endfor %}
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
I assume it is because the validate_on_submit() is called after the form is constructed (again) and thus it does not contain the form fields, and especially not the user inputs. Is there a way to prevent this "data loss" or is this a completely wrong approach?
Also, please let me know if information is missing.
You don't want to validate the form when the page first loads. Try this first:
if request.method == "POST" and form.validate_on_submit():
values = form.parameter
do_stuff(values)
return redirect(url_for('index'))
Next, notice that you are redirecting them to your view for def index():. Is that what you want?

Resources