Django - Dictionary of Forms - javascript

I'm trying to implement a dictionary of forms where two fills are initialized with some values I have. I'm passing this through a Jquery function but when its going to add it to the template, the jquery function has an error that says Cannot set property 'value' of null when trying to execute this document.getElementById('example1').value = example;
My code here:
view.py
def exampleCaesar(request):
if request.is_ajax() and request.method == "GET":
form = caesarCipher(request.GET or None)
if form.is_valid:
wordToEncrypt = request.GET.get('word')
wordToEncrypt = wordToEncrypt.upper()
wordLength = len(request.GET.get('word'))
key = request.GET.get('the_key')
print(wordLength)
print(key)
equations = {}
for x in range(wordLength):
exampleForm = caesarCipher(initial={'letterOfWord' : wordToEncrypt[x], 'key' : key})
##print(exampleForm)
if exampleForm.is_valid:
equations = (exampleForm)
print(equations)
context = { 'equations' : equations
}
return render(request, "content/exampleCaesar.html", context)
Javascript file
$("#encryptButton").on({
click : function() {
var variable = document.getElementById('id_plaintext');
console.log(variable.value)
$.ajax( {
url: "/exampleCaesar",
type : "GET",
data: { CSRF: 'csrf_token',
word: $('#id_plaintext').val(),
the_key: $('#id_key').val()
},
success : function(example) {
$('#example1').show();
$('#example1').html(example);
document.getElementById('example1').value = example;
console.log(example);
}
}); //END OF Ajax
} //END OF FUNCTION
}); //END OF encryptButton
Template file
{% for letterOfWord, key in equations.items %}
<form onsubmit="return false;" method="GET" class="exaSubmit" enctype="multipart/form-data">
{% csrf_token %}
<div id="example1" type="hidden">
( {{ letterOfWord }} + {{ keyToUse }} ) MOD 26 =
{{ letterToFill }} <button name="action" class="validateButton" value="validate"> Validate </button> <br>
</div>
</form>
{% endfor %}
I believe I'm not filling the dictionary the right way. When I try to print it out in the console to see the values, only the names of the fields are but not the values. My bets are in this section but not entirely sure how's that possible when I'm appending the information to it.

Related

Why I can't fetch the json response of django using javascript fetch API?

I am new to JavaScript. I'm working on a project in which I'm using Django in the backend. My Django views function will produce a JSON response which my javascript fetch will get it. Here is my Django views function that produces a JSON response. My motive is to make a like button that will update the like button's appearance and the number of likes by clicking on that button without reloading the whole page. This is the last requirement of my project. I am trying for a long time, a couple of days.
def likepost(request,posts_id):
posts = NewPost.objects.get(id = posts_id)
is_like = False
for like in posts.likepost.all():
if like == request.user and request.method == "POST":
is_like = True
break
if not is_like:
posts.likepost.add(request.user)
else:
posts.likepost.remove(request.user)
posts.save()
# serialize_obj = serializers.serialize("json",posts_id)
return JsonResponse({
"is_like" : is_like,
"num_like" : posts.likepost.count()
},safe=False)
My javascript will make an API of the JSON data generated the above views function using fetch. Here is my javascript full code.
document.addEventListener("DOMContentLoaded",function(e){
// const colon = document.createElement('div');
// colon.setAttribute('id','colon')
e.preventDefault()
// const likebtn = document.createElement('button');
// likebtn.setAttribute('class','likebtn btn btn-primary');
// likebtn.setAttribute('class','likebtn');
// document.querySelector('.card-footer').appendChild(likebtn);
// document.querySelector('.likebtn').innerHTML = "Like";
document.querySelector(`#likebtn${posts_id}`).onsubmit = like_function();
// document.querySelector('.likepost').addEventListener('click', ()=> like_function('likepost'));
})
// let is_like = "{{is_like}}";
// let num_like = "{{num_like}}";
function like_function(){
// document.createElement('button').innerHTML = "Love";
fetch(`/like/${posts_id}`)
// ,{
// method:"POST",
// body : JSON.stringify({
// "is_like" : is_like,
// "num_like" : num_like,
// })
// })
.then(response => response.json())
.then(result => {
if(result.is_like){
document.querySelector(`#likebtn${posts_id}`).innerHTML = "Unike";
// location.replace("http://127.0.0.1:8000")
}
else{
document.querySelector(`#likebtn${posts_id}`).innerHTML = "Like";
// location.replace("http://127.0.0.1:8000")
}
})
}
// function like_function(){
// if (document.querySelector("#like").style.color == "blue"){
// document.querySelector("#like").style.color = "red";
// }else{
// document.querySelector("#like").style.color = "blue";
// }
// }
Here is my urls.py file.
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("profile/<int:id>",views.profilepage,name="profile"),
path("profile/<int:id>/following/addfollower",views.followersPeople,name="addfollower"),
path("profile/<int:id>/following/removefollower",views.followersRemove,name="removefollower),
path("postform", views.createpost, name="postform"),
path("editform/<int:id>",views.editpost,name="editpost"),
path("following",views.followerspost,name="following"),
path("like/<int:posts_id>",views.likepost, name="likepost"),
path("postpage/<int:id>",views.view_post,name="postpage"),
]+ static(settings.MEDIA_URL, document_root= settings.MEDIA_ROOT)
I am also sharing my template here.
{% load static %}
<div class="card-footer">
<form action="{% url 'likepost' posts_id=posts.id %}" class="likeform" method="POST" style="display: inline;">
{% csrf_token %}
<button id="likebtn{{posts.id}}" class="btn btn-link" type="submit">Like</button>
</form>
<small class="num_of_likes">{{ posts.likepost.all.count }}</small>
{% block script %}
<script>
let posts_id = "{{ posts.id }}";
</script>
<script src="{% static 'network/controller.js' %}"></script>
{% endblock %}
<button class="btn btn-link" style="text-decoration: none;">Comment</button>
View Post
{% if request.user.id is posts.user.id %}
Edit
{% endif %}
<div class="likepost"></div>
</div>
My project doesn't work well. When I click on the like button it appears like this
instead of updating the like button into the unlike button and the number of likes as well as the page shouldn't be reloaded. What should I do? Please let me know if I need to share more pieces of code although I see my code is very much messier.
In your video it looks like the form is being sent instead of preventing the POST default.
document.querySelector(`.likeform`).onsubmit = () => like_function();
Look into this answer for more detail about .onsubmit

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");

How to use Flask Jinja Template generated content and JQuery Ajax functionality?

I am creating an app with Flask and JQuery which accepts input from user like this
<form>
{% for i in range(length) %}
<div class="form-group has-success has-feedback">
<label for="question">Question {{ i+1 }}: {{ qlist[i] }}</label>
<textarea class="form-control" rows="5" id="CAT_Custom_{{ i+1 }}" name="CAT_Custom_{{ i }}"></textarea>
<span class="glyphicon glyphicon-ok form-control-feedback"></span>
</div>
{% endfor %}
<input type="submit" name="submit" class="submit action-button" value="Submit" />
</form>
here qlist is a list of questions like this
['What is a Network?', 'What is a Router', ...]
Before submitting the form I want to make sure that each question has an answer of at-least 100 words typed by user. So I'm trying to use a function called process which returns error or success based on the length of answer.
#app.route("/process", methods=["POST"])
def process():
name = request.form['name']
if len(name.split()) >= 100:
return jsonify({'success' : name})
return jsonify({'error': 'No data'})
Now the problem is since my form inputs are dynamically created how do I check if every individual answer is of length 100 words or above.
My attempt was like this but it changes every textarea inputs not just the one with less number of words.
$(function() {
$('form').on('submit', function() {
$.ajax({
data : {
name : $(this).find('.form-control').val()
},
type : 'POST',
url : '/process'
})
.done(function(data) {
if(data.error) {
$('.form-group').find('span').removeClass('glyphicon-ok').addClass('glyphicon-remove');
} else {
$('.form-group').find('span').removeClass('glyphicon-remove').addClass('glyphicon-ok');
}
});
event.preventDefault();
});
});
I found a solution to my problem like this
$(function() {
$('.form-group').focusout( function(event) {
var target = $(this);
$('.form-group').each(function() {
var target = $(this);
$.ajax({
data : {
name : target.find('.form-control').val()
},
type : 'POST',
url : '/process'
}) // Ajax close
.done(function(data) {
if(data.error) {
target.find('span').removeClass('glyphicon-ok').addClass('glyphicon-remove');
} else {
target.find('span').removeClass('glyphicon-remove').addClass('glyphicon-ok');
} // if close
}); // done close
event.preventDefault();
}); // each close
});
});

calling function with ajax, part working but part not working

Sorry if the title isn't very clear. I have search engine that works with ajax function. Right now if I type t in a search box, the tags that contain the word t shows up(ex if I type t, then test shows up) but thing is after I delete the word t all the tags show up in the result part. Does this make sense? if I'm not clear I'll post the picture. I'm not sure why or how to fix this.
Here;s my code.
<h3>Search</h3>
{% csrf_token %}
<input type="text" id="search" name="search" onkeyup="handle_keyup()"/>
<ul id="search-results">
</ul>
Here I can't delete search-results as this will show the search results but on this section when nothing is typed still all the tags show up. (it only shows all when I finish using search bar)
my ajax
function handle_keyup() {
$.ajax({
type: "POST",
url: "/search/",
data: {
'search_text' : $('#search').val(),
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: 'html'
});
};
function searchSuccess(data, textStatus, jqXHR)
{
$('#search-results').html(data);
}
problem is probably occurring from up there, but I'll post the back end as well. This is python django framework.
def search_titles(request):
# categories = SearchQuerySet().autocomplete(content_auto=request.POST.get('search_text', ''))
categories = Category.objects.filter(name__icontains=request.POST.get('search_text', ''))
return render_to_response('main/ajax_search.html', {'categories' : categories})
ajax_Search.html
{% if categories.count > 0 %}
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
{% else %}
<li>None to show!</li>
{% endif %}
thanks in advance
This is happening because when the user "deletes" the word, your handle_keyup function is fired, sending a search request of '' to the server.
The server then looks for the empty string '' in the category names and finds it in all of them.
One approach is for the server to check if the search text is empty, and if it is, return nothing. Something like:
def search_titles(request):
txt = request.POST.get('search_text', '')
if txt:
categories = Category.objects.filter(name__icontains=txt)
else:
categories = []
return render_to_response('main/ajax_search.html', {'categories' : categories})

Django model formsets and Ajax

I am trying to submit my zipped formsets using Ajax. The code works perfectly when the request is not ajax. But whenever I am trying to implement Ajax, I am getting a ValidationError: [u'ManagementForm data is missing or has been tampered with']
My views:
def App(request):
lectures = Lecture.objects.all()
TopicFormSet = modelformset_factory(Topic, extra=0)
SummaryFormSet = modelformset_factory(Summary, extra=0)
tquery = Topic.objects.all()
squery = Summary.objects.all()
#saving formsets:
if request.method == 'POST' and request.is_ajax():
t_formset = TopicFormSet(request.POST)
s_formset = SummaryFormSet(request.POST) #formset instances
if t_formset.is_valid() and s_formset.is_valid():
t_formset.save() and s_formset.save()
zipped = zip(t_formset.forms, s_formset.forms) #saving them with new data
else:
return HttpResponse("not valid formsets, dude") # for testing purposes
else: #request=GET
t_formset = TopicFormSet(queryset = tquery)
s_formset = SummaryFormSet(queryset = squery)
zipped = zip(t_formset.forms, s_formset.forms)
return render (request, "app.html", {"lectures" : lectures, "zipped" : zipped, "t_formset" : t_formset, "s_formset" : s_formset})
And my Javascript code:
$(document).ready(function(){
$(".mygt").click(function(){ // it's a button
serializedData = $("#id_form-0-name").serialize(); // I didn't know how to "catch" all forms in formset so I am only serializing the first one
$.ajax({
url: "/app/",
type: "post",
data: serializedData,
csrfmiddlewaretoken:'{{ csrf_token }}',
success: alert(serializedData)
})
event.preventDefault();
});
});
P.S. I have also included csrf cookie in from this article: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax and {% csrf_token %} is present near the forms.
Edit: my html:
<form action = "http://127.0.0.1:8000/app/" method = "POST">
{% csrf_token %}
<!-- t_formset.management_form -->
{{ t_formset.management_form }}
<!-- t_formset.management_form -->
{{ s_formset.management_form }}
<!-- formsets -->
{% for topic, summary in zipped %}
<div id="topic">{{ topic }}</div>
<br>
<input type="submit" value="Submit" class="mygt" />
<br>
<div id="summary">{{ summary }}</div>
<br>
<input type="submit" value="Submit" class="mygt" />
{% endfor %}
The problem was that I did not know how to serialize all formset and I was only serializing the first field (for testing purposes). I was not aware of the fact that Django sends all formset and not just one field like I thought. So I replaced the
serializedData = $("#id_form-0-name").serialize();
with:
serializedData = $("form").serialize();
And the code works!
Did you include {{t_formset.management_form}} and {{s_formset.management_form}} in your template as described here?I had the same problem and i got the same answer here

Categories

Resources