How to use the value of <select> in with django function? - javascript

So I want to make a function with if in my html using django.
My function looks like :
function try() {document.getElementById("demo").inerHTML = '{%for x in xl%}'+
'{%if x.name == document.getElementById("select1").value%}'+
'<button type="button">hello</button>'+
'{%endif%}{%endfor%}'}
And the relevant html is :
<select id="select1">
<option value = "tiger"></option>
<option value = "bear"></option>
<option value = "eagle"></option>
</select>
<p id="demo"></p>
<script>try();</script>
So just to make it clear :
'xl' is a list, the items in this list have a name variable.
I want my web to show in the "demo" paragraph 'hello' buttons for each time that the selcted animal is the name of item in the list.
When trying to run this it says : " Could not parse the remainder: '("select1").value;' from 'document.getElementById("select1").value;' "
Please help me find what`s wrong and how to fix it, Thanks.

Why not just use a Django form, and then get the selected option value with JavaScript? Example code has not been tested. You still need an app within your Django project, settings, templating, routing, etc.
# forms.py
class AnimalForm(forms.Form):
TIGER = 'Tiger';
BEAR = 'Bear'
EAGLE = 'Eagle'
ANIMAL_CHOICES = (
(TIGER, TIGER,),
(BEAR, BEAR,),
(EAGLE, EAGLE,),
)
animal = forms.CharField(max_length=20, choices=ANIMAL_CHOICES,
default=TIGER)
def save(self):
return NotImplementedError
# implement
# views.py
from django.shortcuts import render
from .forms import AnimalForm
def choose_animal(request):
form = AnimalForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
# do something, like redirect to a success page, etc
return render(request, 'animal_form.html',
{'form': form})
#animal_form.html
<form action="." method="post" enctype="application/x-www-form-urlencoded">
{{ form.animal }}
<button type="submit">Save</button>
</form>
<p id="animal-selection"></p>
<script>
// assuming jQuery is already linked for brevity
(function($) {
$(function() {
$('#id_animal').on('change', function() {
$('#animal-selection').html($(this).val());
});
});
})(jQuery);
</script>

Related

How to prefill django form Dynamically

I am trying to display a form in django and pre-filling it dynamically.
I want the user of my sample news gathering site to modify an entry.
I have my Manual Input form class
#forms.py
class ManualInputForm(forms.Form):
source = forms.CharField(label="Source:", widget = forms.TextInput(attrs={'size': 97}))
topic = forms.CharField(label="Topic:", widget = forms.TextInput(attrs={'size': 97}))
news = forms.CharField(widget = forms.Textarea(attrs={"rows":5, "cols":100}))
link = forms.CharField(label="Link (optional):", required = False, widget = forms.TextInput(attrs={'size': 97}))
In the HTML I am going manually because I would like to pre-fill all fields with data coming in from the related function in views.py.
#html file
<form method="post" class="form-group">
{% csrf_token %}
<div class="input-group mb-3">
<div class="container">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}
<br>
{{ field }}
</div>
{% endfor %}
</div>
<div class="input-group">
<p> </p>
<button type="submit" class="btn btn-success" name="Submit">Save</button>
</div>
</div>
</form>
How do I do it? It's driving me crazy o.O
I would like to keep using django's forms because of its integrated error manager (not all fields are required but some are and I'd like for django to keep managing it).
Thank your for your suggestions!
EDIT:
as requested I'll post the views.py related function:
#views.py
def editnews(response, id):
form = ManualInputForm(response.POST or None)
#tableToView is a dataframe retrieved by querying an external DB
#data cannot be stored in django's buit in because of reasons ;-)
#checking the dataframe is correct and it is:
#IT IS MADE OF A SINGLE LINE
print(tableToView)
#THIS IS PROBABLY NOT THE WAY TO DO IT
form.source = tableToView.loc[0, 'Source']
form.topic = tableToView.loc[0, 'Topic']
form.news = tableToView.loc[0, 'News']
form.link = tableToView.loc[0, 'Link']
return render(response, 'manual/editnews.html', {"form":form})
In the image the text should be pre-filled.
Try something like that:
def editnews(response, id):
data = {k.lower(): v for k, v in tableToView.loc[0].to_dict().items()}
form = ManualInputForm(response.POST or None, initial=data)
return render(response, 'manual/editnews.html', {'form': form})
when you are declaring or rendering form in view and sending it to template. use initial argument and pass dictionary in it with key as name of field and value as the text which you want prefilled.
like this
context['form'] = NameofForm(initial={'Source':'mysite', 'Topic':'mytopic'})
return context
Update
> def test_view(request, pk):
> template_name = 'form.html'
> form = MyForm(initial={"test":"initialize with this value"})
> if request.method == 'POST':
> form = MyForm(request.POST)
> if form.is_valid():
> form.save()
> return HttpResponseRedirect(reverse('list-view'))
>
> return render(request, template_name, {'form': form})
Try this:
#views.py
def editnews(response, id):
data = {}
data["source"] = tableToView.loc[0, 'Source']
data["topic"] = tableToView.loc[0, 'Topic']
data["news"] = tableToView.loc[0, 'News']
data["link"] = tableToView.loc[0, 'Link']
form = ManualInputForm(response.POST or None, initial=data)
return render(response, 'manual/editnews.html', {"form":form})
You could do it with jQuery if you're using one. You'll need to set the attribute of id to the form field.
jQuery code example:
$('#topic').val("Prefilled text goes here");

Jquery submit() not submitting form data to my view

I have the following file (app.py) that generates a Flask instance and defines a few routes and declares/initiates a simple form:
from flask import Flask, render_template, url_for
from flask_wtf import FlaskForm
import wtforms as wtf
from wtforms.fields.html5 import DecimalRangeField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'youll-never-guess'
class Form(FlaskForm):
age = DecimalRangeField('age', default=30)
submit = wtf.SubmitField('submit')
#app.route('/form/', methods=['GET'])
def form():
form = Form()
return render_template('form.html', form=form)
#app.route('/form/submit/', methods=['POST'])
def submit_form():
return 'form submitted!'
def main():
app.run(debug=True, port=5000)
if __name__ == '__main__':
main()
where the templates/form.html file is as follows:
<form id="form" action="{{ url_for('submit_form') }}" method="POST" onchange="submitForm(this);">
{% for field in form %}
{{ field }}
{% endfor %}
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
function submitForm(form) {
console.log(`submitting form ${form} ... `);
$(form).submit();
}
</script>
When I change the slider the console prints submitting form [object HTMLFormElement] ... but does not seem to call the view function submit_form. However, when I click the submit button the /form/submit/ URL is rendered with the text form submitted!. Why is this, please?
You have to rename submit field on the form because submit method/handler is shadowed by the name/id attribute.
class Form(FlaskForm):
age = DecimalRangeField('age', default=30)
sub = wtf.SubmitField('sub')
Alternatively you can add your form button directly in the template but it can't have id nor name submit.
In your code, the change method has a call back function and inside this call back function, this refers to the current call back function scope, which doesn't have any submit method.
Therefore, fetch the form object using JQuery or vanilla JS as follows:
var form = document.getElementById("form");
$(form).submit();

render a flask MultipleSelectField with selected values highlighted

In my flask app, I need to render a form that has a MultipleSelectField with some already selected options. I have done this successfully but the problem is that they are not highlighted and thus the user can't know which options are already selected which can also enable them be deselected.
Any ideas on how I can get this done from the backend or even using vanilla javascript.
Here is the view function that renders the form:
#home.route('/edit/<int:id>', methods=['GET', 'POST'])
#login_required
def edit_post(id):
post = Post.query.get_or_404(id)
if current_user != post.author and not current_user.can(Permission.ADMINISTER):
abort(403)
form = PostForm()
form.tag.choices = [(tag.id, tag.name) for tag in Tag.query.order_by('name')]
if form.validate_on_submit():
post.body = form.body.data
posttags = db.session.query(categories).filter_by(post_id=id).all()
for id in form.tag.data:
if (post.id, id) not in posttags:
post.tags.append(Tag.query.get(id))
db.session.commit()
return redirect(url_for('.view_post', id=post.id))
form.body.data = post.body
# already selected values
form.tag.data = [tag_id for tag_id in db.session.query(categories).filter_by(post_id=post.id).all()]
return render_template('home/edit_post.html', form=form, title='Edit Post')
Have done some research. So, in a nutshell, how can I add the selected attribute to the pre-selected options.

Dynamically update Django form field options using Ajax to GET new queryset

I'm new to coding and django and I'm struggling to find the solution to the following problem having reviewed the answers I've found.
Im creating a search form with multiple fields. When the user selects the first field category (and before hitting search) I would like to dynamically change the queryset for the second field sub_category such that only related values are shown.
I have models.py as follows:
class Product(models.Model):
category = models.ForeignKey("Category")
sub_category = models.ForeignKey("SubCategory")
class Category(models.Model):
name = models.CharField(max_length=256)
class SubCategory(models.Model):
category = models.ForeignKey("Category")
name = models.CharField(max_length=256)
And my forms.py includes:
class BasicSearchForm(forms.Form):
category = forms.ModelChoiceField(
label='Category',
queryset=Category.objects.all(),
to_field_name="name",
empty_label=None,
initial="Red")
sub_category = forms.ModelMultipleChoiceField(
required=False,
label='Type',
queryset= SubCategory.objects.all(),
to_field_name="name",
widget=forms.Select)
And my views.py includes:
def search(request):
if request.method == 'POST':
form = BasicSearchForm(request.POST)
if form.is_valid():
category = form.cleaned_data['category']
sub_category = form.cleaned_data['sub_category']
return render(request, 'myapp/search.html', {'form': form})
else:
form = BasicSearchForm()
return render(request, 'myapp/search.html', {'form': form})
And finally the search.html includes:
<form class="search-form" role="search" action="/search/" method="get">
{{ form }}
<input type="submit" value="Search" />
</form>
I've played around with a few answers but nothing seems to work. I'd really appreciate some help. Thanks in advance!
Update:
Thanks for the feedback. As a result I updated the following:
In my urls.py:
urlpatterns = [
url(r'^ajax/update_subcategories/$', views.update_subcategories, name='update_subcategories'),
And in my views.py:
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(sub_category, safe=False)
And I have this in my myapp/search.html:
{% block javascript %}
<script>
$("#id_category").change(function () {
var category = $(this).val();
$.ajax({
url: '{% url "myapp:update_subcategories" %}',
data: {
'category': category,
},
success: function (response) {
var new_options = response;
alert(new_options[0].name); // works
$('#id_sub_category').empty();
$.each(new_options, function(key, value) {
$('#id_sub_category')
.append($('<option>', { value : key })
.text(value.name));
});
}
});
</script>
{% endblock %}
Update: The sub_category options were showing as [object Object] until I changed value to value.name and it looks like it's working. I'll test it out and close unless there are any comments.
Update: Im still having an issue with the browser back button. When a user clicks back the dropdown values have changed back to the original queryset rather than the updated version.
You can't do this from Django views side, ie, backend. You could try an ajax request for implementing this kind of requests, by sending a GET request to the server for populating the drop-down or whatever you are into.
For a simple example, you could refer
here
How do I POST with jQuery/Ajax in Django?
EDIT
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(dict(sub_category=sub_category))
Then in ajax response you could grab it like response.data.sub_category
Use ajax to send the category and retrieve subcategory elements.
For the category, send it via get request, and using the orm return the subcategories in a json format which you can show using jQuery.

Django Ajax Update Div without Refresh

I'm trying to update <strong id="vote_count"> without having the refresh the page. Currently, the ajax request gets posted, but I have to manually refresh to page to update the vote count. recommendation.get_total_votes is originally a function in recommendation model.
html
<div id="vote_count">Vote Count: {{ recommendation.get_total_votes }}</div>
<br>
<button class="upvotes" data-recommendation="{{ recommendation.id }}" class="btn btn-primary" type="button">
<span class="glyphicon glyphicon-thumbs-up"></span>
Upvote1
</button>
ajax.js
$(document).on("click", ".upvotes", function(){
console.log('my message');
var recommendationid = $(this).attr("data-recommendation");
$.post('/upvote/', {recommendation_id: recommendationid}, function(data){
console.log('my message1');
$('#vote_count').html(data);
$('#upvotes').hide();
});
});
views.py
#csrf_exempt
#login_required
def upvote(request):
recommendation_id = None
if request.method == 'POST':
recommendation_id = request.POST['recommendation_id']
get_total_votes = 0
if recommendation_id:
recommendation = coremodels.Recommendation.objects.get(id=int(recommendation_id))
user = request.user
recommendation.votes.up(user)
get_total_votes = recommendation.votes.count()
return HttpResponse(get_total_votes)
models.py (edit):
class Recommendation(models.Model):
topic = models.ForeignKey(Topic)
user = models.ForeignKey(User)
title = models.CharField(max_length=300)
votes = VotableManager()
def get_total_votes(self):
total = self.votes.count()
return int(total)
Thanks for all the trouble shooting. I was able to work around this issue by changing
$('#vote_count').html(data);
$('#upvotes').hide();
to
$('.vote_count').html(data);
$('.upvotes').hide();
And use class instead of id tags in html. Still unsure why id tags are not working.

Categories

Resources