I'm trying to validate a simple form with Django and it seems that it always returns false. I'm sending the value of the form via AJAX to the views.py and also printing the value in the Javascript and the view.py just to be sure it passed correctly.
The views file:
def change_alphabet(request):
cipher = CaesarCipher()
x = cipher.getListLetter()
y = cipher.getListLetter()
if request.is_ajax() and request.method == "GET":
print("Inside CHANGE")
formKey = caesarKey(request.GET or None)
print("Valid or not: %r " % formKey.is_valid())
integerKey = int(request.GET.get('the_key'))
print(integerKey)
if formKey.is_valid():
print(request.GET.get('the_key'))
integerKey = int(request.GET.get('the_key'))
y = cipher.setCipherLetters(integerKey)
context = { 'x': x,
'y': y,
'formKey': formKey,
}
return render(request, "content/alteredAlphabet.html", context)
else:
print(formKey.errors)
context = { 'x': x,
'y': y,
'formKey': formKey,
}
return render(request, "content/alteredAlphabet.html", context)
The form:
class caesarKey(forms.Form):
key = forms.DecimalField(max_value = 26, min_value = 1, initial = 1, required = True, error_messages={'required' : 'Please input a valid key number!'}, widget=forms.NumberInput(attrs={'class' : 'form-control', 'placeholder' : 'Key'}))
The Javascript:
$("#keyButtonId").on({
click: function() {
var variable = document.getElementById('id_key');
console.log(variable.value)
$.ajax({
url: "/alteredAlphabet",
type: "GET",
data: {
CSRF: 'csrf_token',
the_key: $('#id_key').val()
},
success: function(json) {
// $('#id_key').val('0');
// console.log(json);
$('#letterSection').fadeOut('slow', function() {
$('#letterSection').html(json);
$('#letterSection').fadeIn(3000);
});
//document.getElementById('letterSection').value = json;
console.log("FUNCTION CALLED!");
}
});
}
});
The error that is printed is:
<ul class="errorlist"><li>key<ul class="errorlist"><li>Please input a valid key number!</li></ul></li></ul>
UPDATE:
Template code for rendering the form:
<label for="id_key">
Key:
</label>
<form onsubmit="return false;" method="GET" id="key-form">
{% csrf_token %}
<div class="col-sm-2 col-xs-5">
{{ formKey.key }}
</div>
<button name="action" id="keyButtonId" class="btn btn-primary" value="key">Key</button>
</form>
{% if formKey.errors %}
<div class="alert alert-danger" role="alert">
<strong>{{ formKey.key.errors }}</strong>
</div>
{% endif %}
Why is it always returning false? Am I missing an additional phase of bounding the data?
You're passing your key data as the_key in the Ajax, but the form is expecting just key.
Related
I am trying to pass the values of form data through ajax .And getting method not allowed error. I am trying to add comment in a blog post.
This is my form which is inside blog_detail page
<form id="commentform" class="commentform" method="post">
{% csrf_token %}
{%with allcomments.count as total_comments%}
<p>
{{total_comments}} comment{{total_comments|pluralize}}
</p>
{%endwith%}
<select name="blog" class="d-none" id="id_blog">
<option value="{{blog.id}}" selected="{{blog.id}}"></option>
</select>
<label class="small font-weight-bold">{{comment_form.parent.label}}</label>
{{comment_form.parent}}
<div class="d-flex">
<img class="avatar_comment align-self-center" src="{% for data in avatar%}{{data.avatar.url}}{%endfor%}" alt="">
{{comment_form.content}}
</div>
<div class="d-flex flex-row-reverse">
<button value="commentform" id="newcomment" type="submit" class="newcomment btn btn-primary">Submit</button>
</div>
</form>
And when I click the button it should call the ajax
$(document).on('click','#newcomment',function(e){
e.preventDefault();
var button =$(this).attr("value");
var placement = "commentform"
if (button=="newcommentform"){
var placement = "newcommentform"
}
$.ajax({
type: 'POST',
url: '{% url "website:addcomment" %}',
data: $("#" + button).serialize(),
cache: false,
sucess: function(json){
console.log(json)
$('<div id="" class="my-2 p-2" style="border: 1px solid grey"> \
<div class="d-flex justify-content-between">By ' + json['user'] + '<div></div>Posted: Just now!</div> \
<div>' + json['result'] + '</div> \
<hr> \
</div>').insertBefore('#' + placement);
},
error: function(xhr,errmsg,err){
}
});
})
This is my urls.py
path('blog/<int:blog_id>', BlogDetails.as_view(), name="blog_detail"),
path('addcomment/',addcomment, name="addcomment"),
and my views.py is:
class BlogDetails(View):
def get(self, request, blog_id):
query = request.GET.get('query')
if query:
return redirect(reverse('website:search') + '?query=' + query)
blog = Blog.objects.get(id=blog_id)
total_comment = Comment.objects.filter(blog=blog).count()
allcomments = blog.comments.filter(status=True)
blog_list = Blog.objects.all()
comment_form = NewCommentForm()
data = {
'blog': blog,
'blog_list': blog_list,
'total_comment': total_comment,
'comment_form': comment_form,
'allcomments': allcomments
}
return render(request, "blog_detail.html", data)
def addcomment(request):
if request.method == 'post':
comment_form = NewCommentForm(request.POST)
print(comment_form)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.user = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
Please help me with this it is not calling addcomment view
If how I've interpreted your code is correct, it would probably work if changed your BlogDetails class to this:
class BlogDetails(View):
def get(self, request, blog_id):
query = request.GET.get('query')
if query:
return redirect(reverse('website:search') + '?query=' + query)
blog = Blog.objects.get(id=blog_id)
total_comment = Comment.objects.filter(blog=blog).count()
allcomments = blog.comments.filter(status=True)
blog_list = Blog.objects.all()
comment_form = NewCommentForm()
data = {
'blog': blog,
'blog_list': blog_list,
'total_comment': total_comment,
'comment_form': comment_form,
'allcomments': allcomments
}
return render(request, "blog_detail.html", data)
def post(self, request, *args, **kwargs):
return self.addcomment(request)
def addcomment(self, request):
comment_form = NewCommentForm(request.POST)
print(comment_form)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.user = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
Because you are trying to POST to a view that doesn't have a post method defined.
Then you would need to remove addcomment from the URL you are calling and just post to whatever URL you are currently at.
I want to display countries and states in Django form, for that I am trying to get data from json, create form, pass json data to form and get state of the country on ajax request. I managed to write the process as far as I learned, but at last form is not rendered on Django template. How can I render Django form with following code structure?
My Model:
from django.db import models
class Address(models.Model):
country = models.CharField(null=True, blank=True, max_length=100)
state = models.CharField(null=True, blank=True, max_length=100)
def __str__(self):
return '{} {}'.format(self.country, self.state)
My Forms.py:
import json
def readJson(filename):
with open(filename, mode="r", encoding="utf-8") as fp:
return json.load(fp)
def get_country():
""" GET COUNTRY SELECTION """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_countries = [('-----', '---Select a Country---')]
for x in all_data:
y = (x['name'], x['name'])
all_countries.append(y)
return all_countries
def return_state_by_country(country):
""" GET STATE SELECTION BY COUNTRY INPUT """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_states = []
for x in all_data:
if x['name'] == country:
if 'states' in x:
for state in x['states']:
y = (state['name'], state['name'])
all_states.append(state['name'])
else:
all_states.append(country)
return all_states
class AddressForm(forms.ModelForm):
country = forms.ChoiceField(
choices = get_country(),
required = False,
label='Country / Region*',
widget=forms.Select(attrs={'class': 'form-control', 'id': 'id_country'}),
)
class Meta:
model = Address
fields = ['country']
My Form.html
<form class="" action="" method="post">
{% csrf_token %}
{% for error in errors %}
<div class="alert alert-danger mb-4" role="alert">
<strong>{{ error }}</strong>
</div>
{% endfor %}
<div class="row">
<div class="col-lg-6">
<div class="mb-4">
{{ form.country}}
</div>
</div>
<div class="col-lg-6">
<div class="mb-4">
<div class="form-group">
<label >Select a Province/State</label>
<select id="id_province" class="form-control" name="state">
<option value="-----">Select Province/State</option>
</select>
</div>
</div>
</div>
</div>
</form>
My Views:
def readJson(filename):
with open(filename, mode="r", encoding="utf-8") as fp:
return json.load(fp)
def return_state_by_country(country):
""" GET STATE SELECTION BY COUNTRY INPUT """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_states = []
for x in all_data:
if x['name'] == country:
if 'states' in x:
for state in x['states']:
y = (state['name'], state['name'])
all_states.append(state['name'])
else:
all_states.append(country)
return all_states
def getProvince(request):
country = request.POST.get('country')
provinces = return_state_by_country(country)
return JsonResponse({'provinces': provinces})
def processForm(request):
context = {}
if request.method == 'GET':
form = AddressForm()
context['form'] = form
return render(request, './ecommerce/checkout.html', context)
if request.method == 'POST':
form = AddressForm(request.POST)
if form.is_valid():
selected_province = request.POST['state']
obj = form.save(commit=False)
obj.state = selected_province
obj.save()
return render(request, './ecommerce/checkout.html', context)
My Ajax:
<script>
$("#id_country").change(function () {
var countryId = $(this).val();
$.ajax({
type: "POST",
url: "{% url 'ecommerce:get-province' %}",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'country': country
},
success: function (data) {
console.log(data.provinces);
let html_data = '<option value="-----">Select Province/State</option>';
data.provinces.forEach(function (data) {
html_data += `<option value="${data}">${data}</option>`
});
$("#id_province").html(html_data);
}
});
});
</script>
I am trying to print form.country on template but its not working. What could be the problem?
With ModelForms I find that this type of configuration, in which everything falls under class Meta: works.
However im dubious about that get_country() method. If you share it I can take a deeper look and maybe even test it to make sure that it's not doing anything funky.
If your list of countries is somewhat static and not too long you might wanna consider using a TextChoices enum type in your model attribute to limit the choice selection. Django forms will automatically render a dropdown widget listing the items from your enum.
You can checkout this answer if you want to look into that, which further links to the django docs.
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['country']
widgets = {
"country": forms.ChoiceField(
choices = get_country(),
attrs={
"class": "form-control",
"id": "id_country"
}
),
}
labels = {
"country" : "Company Country Location"
}
i'm struggling to make ajax function that change the boolean value of an object without refreshing the page.
It returns error 500.
Model:
class Donation(models.Model):
is_taken = models.BooleanField(default=False)
HTML:
<div style="width: 50%; float:left" class="steps--container">
{% for d in taken %}
<div style="width: 80%; float: left">
<h4>{{d.quantity}} bags of {% for c in d.categories.all %} {{c}} {% endfor %} by {{d.user.first_name}} {{d.user.last_name}} </h4>
<input type="text" id="donation_id" value={{d.id}} hidden>
</div>
<div style="width: 20%; float:right">
<input type="button" onclick="updateStatus()" value="{{d.id}}" Mark as not taken>
</div>
<br>
{% endfor %}
</div>
JS:
function updateStatus() {
var dId = document.getElementById("donation_id").value;
var dIdInt = parseInt(dId, 10)
$.ajax({
type: "GET",
url: "/ajax/taken_or_not_taken/",
data: {
"donation_id": dIdInt
}
}).done(function(e){
console.log("done")
console.log(dIdInt)
})
.fail(function(e){
console.log('error')
console.log(e)
})
}
View:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse(obj)
Url:
url(r'^ajax/taken_or_not_taken/$', views.taken_or_not_taken, name='taken_or_not_taken'),
How can i make it works?
The full stacktrace says :
line 121, in taken_or_not_taken return JsonResponse(obj)
line 555, in __init__'In order to allow non-dict objects to be serialized set the the safe parameter to False.'
JsonResponse() should have a dict in argument and you pass an integer.
You can use the donation_id name:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse({'donation_id':obj})
Or use the safe=False parameter : https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.JsonResponse
Yea, i found it out, thanks guys anyway,
But the new problem appeared.
User still needs refresh the page to see the changes.
How to do it without refreshing page? Can i do it in django view?
Like:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id')
data = {
"id": obj
}
donate = Donation.objects.get(id=obj)
if donate.is_taken == True:
donate.is_taken = False
donate.save()
elif donate.is_taken == False:
donate.is_taken = True
donate.save()
return JsonResponse(data)
You can use ajax "POST" method to send the query to the server without refreshing the page.
$.ajax({
type: "POST",
url: "url_of_query",
data: {
// Data you want to update
}
success: function(){
console.log("Success msg");
},
error: function(){
console.log("error");
},
)}
My autocomplete form works fine if I populate the list manually. However, If I populate from db the dropdown list does not populate.
HTML/JS
<div style="text-align: center;">
{% from "_formhelpers.html" import render_field %}
<form method="POST" action="/">
<dl id="autocomplete" style="display:inline-block;"> .
{{render_field(form.search) }}
</dl>
<button id="searchbutton" type="submit" style="display: inline-block;" class="btn btn-outline-success my-2 my-sm-0" onclick="fetchlist(); return false;">Search</button>
</form>
</div>
<script>
$(function() {
$("#autocomplete").autocomplete({
source:function(request, response) {
$.getJSON("{{url_for('autocomplete')}}",{
q: request.term,
}, function(data) {
response(data.cities);
});
},
minLength: 2,
select: function(event, ui) {
console.log(ui.item.value);
}
});
})
function fetchlist() {
if (document.getElementById('searchbutton').onclick) {
document.getElementById('list').style.display = 'inline';
}
else document.getElementById('list').style.display = 'inline';
}
Flask
#app.route('/_autocomplete', methods=['GET'])
def autocomplete():
c, conn = connection()
qry = "SELECT Distinct PhoneNumber FROM webappdb.posts"
c.execute(qry)
x = c.fetchall()
cities= list(chain.from_iterable(x))
#cities = [x for x in c.fetchall()]
print(cities)
'''
cities = [
"123",
"12"]'''
return Response(json.dumps(cities), mimetype='application/json')
#app.route('/', methods=['GET', 'POST'])
def homepage():
try:
form=SearchForm(request.form)
global d1
d1 =""
if request.method == "POST":
s1 = form.search.data
c,conn = connection()
qry = "SELECT FirstName, LastName FROM posts WHERE PhoneNumber LIKE (%s)"
c.execute(qry, s1)
d1 = c.fetchall()
c.close()
conn.close()
print(d1)
else: print('error')
return render_template("index.html", data=d1, form = form)
except Exception as e:
return(str(e))
Ideally, i'd like a user to being typing and the autocomplete returns and filters data in the database. Once the user finds what they are looking for, it would pull information based on that person's phone number.
I am trying to have the user's chosen item be shown in the FilteredSelectMultiple chosen box when he/she revisits the page.I've tried appending options via javascript but that didn't help. I have seen a stackoverflow question on how to pre-populate the same widget as well but that seems to be for the Admin side only. My FilteredSelectMultiple widget is on the user side.
Here is the code I used:
models.py:
class Roles(models.Model):
role_id = models.AutoField(primary_key=True)
role_name = models.CharField(max_length=18,
unique=True,
validators=[letters_only])
class Staffs(models.Model):
staff_id = models.AutoField(primary_key=True)
admission_number = models.CharField(max_length=5,
unique=True,
help_text="Enter 5 digits",
validators=[numeric_only, MinLengthValidator(5)])
staff_full_name = models.CharField(max_length=70,
help_text="Enter staff's full name",
validators=[letters_only])
created_by = UserForeignKey(auto_user_add=True,
editable=False,
related_name="staff_created_by",
db_column="created_by")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_by = UserForeignKey(auto_user=True,
editable=False,
related_name="staff_updated_by",
db_column="updated_by")
updated_at = models.DateTimeField(auto_now=True,
editable=False)
roles = models.ManyToManyField(Roles, through='Designations')
class Designations(models.Model):
designation_id = models.AutoField(primary_key=True)
curriculum = models.ForeignKey(Curricula, on_delete=models.CASCADE)
role = models.ForeignKey(Roles, on_delete=models.CASCADE)
staff = models.ForeignKey(Staffs, on_delete=models.CASCADE)
forms.py:
class ModuleCoordinatorForm(forms.ModelForm):
class Media:
css = {
'all': ('admin/css/responsive.css', 'admin/css/base.css', 'admin/css/widgets.css',)
}
js = ('/admin/jsi18n',)
class Meta:
model = Designations
fields = ['module_coordinator', 'role_mc']
module_coordinator = forms.ModelMultipleChoiceField(queryset=Staffs.objects.all(),
widget=FilteredSelectMultiple("Module Coordinator",
is_stacked=False),
required=False,
label="")
role_mc = forms.ModelChoiceField(queryset=Roles.objects.all(), widget=forms.HiddenInput,
initial=Roles.objects.get(role_name='Module Coordinator'))
views.py:
def module_coordinator(request):
c = request.GET.get('curriculum')
c = int(c)
mc = request.GET.get('mc')
staffs = request.GET.get('staffs')
staffs = staffs.replace('[', '')
staffs = staffs.replace(']', '')
staffs = staffs.split(",")
staffs = [i.replace('"', '') for i in staffs]
staffs = [ast.literal_eval(i) for i in staffs]
# code for saving into db
if request.is_ajax:
for staff in staffs:
if Designations.objects.filter(curriculum_id=c, role_id=mc, staff_id=staff).exists():
pass
else:
Designations(curriculum_id=c, role_id=mc, staff_id=staff).save()
data = {
'result': 'Module Coordinators Assigned Successfully'
}
return JsonResponse(data)
class DesignationsView(TemplateView):
template_name = 'curricula/designations.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['mc_form'] = ModuleCoordinatorForm(self.request.GET or None)
context['curriculum'] = Curricula.objects.get(
course_period__course__course_abbreviation=self.kwargs.get('course_abbr'),
module_period__module__module_abbreviation=self.kwargs.get('module_abbr'),
course_period__period__academic_year=self.kwargs.get('year'),
course_period__period__semester=self.kwargs.get('semester'),
stage=self.kwargs.get('stage')).pk
mc_qs = Designations.objects.filter(role__role_name='Module Coordinator',
curriculum__course_period__course__course_abbreviation=self.kwargs.get(
'course_abbr'),
curriculum__module_period__module__module_abbreviation=self.kwargs.get(
'module_abbr'),
curriculum__course_period__period__academic_year=self.kwargs.get('year'),
curriculum__course_period__period__semester=self.kwargs.get('semester'),
curriculum__stage=self.kwargs.get('stage')
).values_list('staff', flat=True)
chosen_mcs_name = []
chosen_mcs_id = []
for mc in mc_qs:
chosen_mc = Staffs.objects.get(pk=mc)
chosen_mcs_name.append(chosen_mc)
chosen_mcs_id.append(mc)
# print(chosen_mcs_name)
print(chosen_mcs_id)
# chosen_mcs_name_json = json.dumps(chosen_mcs_name)
# print(chosen_mcs_name_json)
context['chosen_mc_name'] = chosen_mcs_name
context['chosen_mc_value'] = chosen_mcs_id
return context
urls.py:
path('courses/<str:course_abbr>/<str:module_abbr>/<int:year>/<int:semester>/<int:stage>/designations',
views.DesignationsView.as_view(), name='designations'),
path('ajax/module_coordinator/', views.module_coordinator, name="module_coordinator")
designations.html:
{% extends "main_template.html" %}
{% load static %}
{% block title %}Designations{% endblock %}
{% block css %}
<style>
hr {
display: block;
margin: 0.5em auto;
border: 1px inset;
}
</style>
{% endblock %}
{% block content %}
{% include 'navbar_architect.html' %}
{{ mc_form.media }}
<div id="content" class="colM">
<div id="content-main">
<h2>Assign Module Coordinator(s)</h2>
<form enctype="multipart/form-data" method="post" novalidate>
{% csrf_token %}
{{ mc_form.non_field_errors }}
<input type="hidden" value="{{ curriculum }}" id="id_curriculum_mc">
{{ mc_form.role_mc }}
<div>
<fieldset class="module aligned">
<div class="form-row">
<div>
<div class="fieldWrapper related-widget-wrapper">
<div class="selector">
{{ mc_form.module_coordinator.errors }}
{{ mc_form.module_coordinator }}
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-primary float-right" id="mc_btn">Assign</button>
</fieldset>
</div>
</form>
<hr>
</div>
</div>
{% endblock %}
{% block javascript %}
<script>
$(document).ready(() => {
let value = "{{ chosen_mc_value }}";
value = value.replace('[', '');
value = value.replace(']', '');
value = value.split(",").map(Number);
console.log(value);
let name = "{{ chosen_mc_name }}".replace(/<Staffs: /g, '');
name = name.replace(/>/g, '');
name = name.replace('[', '');
name = name.replace(']', '');
name = name.split(", ");
console.log(name);
for (let i = 0; i < value.length; i++) {
$("#id_module_coordinator_to").append(`<option value="${value[i]}">${name[i]}</option>`); //doesn't work
}
$('#mc_btn').click(function () {
$('#id_module_coordinator_to option').prop('selected', true);
let curriculum = $("#id_curriculum_mc").val();
let mc = $("#id_role_mc").val();
let staffs = $("#id_module_coordinator_to").val();
if ($("#id_module_coordinator_to").has('option').length === 0) {
return false;
}
$.ajax({
url: '{% url 'module_coordinator' %}',
data: {
'curriculum': curriculum,
'mc': mc,
'staffs': JSON.stringify(staffs)
},
dataType: 'json',
success: function (data) {
swal({
title: data.result,
toast: true,
position: 'top-end',
type: 'success',
showConfirmButton: false,
allowEscapeKey: false,
allowOutsideClick: false,
backdrop: false,
timer: 1500,
})
},
error: function () {
swal({
title: "Unable to assign",
toast: true,
position: 'top-end',
type: 'error',
showConfirmButton: false,
allowEscapeKey: false,
allowOutsideClick: false,
backdrop: false,
timer: 1500,
})
}
});
});
});
</script>
{% endblock %}
Note: swal is a Javascript alert notification library
Try this in forms
class ModuleCoordinatorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ModuleCoordinatorForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['module_coordinator'].initial = self.instance.staff.all()
self.fields['role_mc'].initial = self.instance.role.all()
or this in views
def edit_designations(request, id_designation):
if request.method == 'GET':
designation = get_object_or_404(Designations, pk=id_designation)
form = ModuleCoordinatorForm(instance=designation)
form.fields['module_coordinator'].initial = form.instance.staff.all()
form.fields['role_mc'].initial = form.instance.role.all()
return render(request, 'designation.html', {'form': form})