Saving an Entity using json in Google App Engine NDB Datastore - json

Hello Developers I am using Python Flask , Knockout.js and Google App Engine. Now I am making the basic program which is poster I am just posting some stuff using poster. But It seems that Google App Engine Datastore does not takes the values from request.json['...']
when form.validate_on_submit() is also in if condition of the view.
Here is my Flask View code
#app.route('/post/new',methods=['POST','GET'])
def post_it():
form = CreatePost(request.form)
use_db = ndb.Key(model.User, current_user.name)
if **form.validate_on_submit()** and request.method=='POST':
posting = model.Post(
name = use_db,
poster = request.json['post'],
postbody = request.json['postbody'],
posturl = request.json['posturl'],
)
try:
posting.put()
flash("Poster has been populated", category='info')
return jsonify({ "post": request.json['post'],"postbody": request.json['postbody'], "posturl": request.json['posturl'] })
except CapabilityDisabledError:
flash('Error Occured while posting')
return redirect(url_for('post_it'))
return render_template('poster.html', form=form, use_db = use_db, post_db = post_db)
#app.route('/posts',methods=['GET'])
def all_posts():
post_db = model.Post.query()
return jsonify(post_db=post_db)
My poster.html code
<form id="new_postform" action="{{ url_for('post_it') }}" data-bind="submit: addPost" class="navbar-form form-inline" method="post" >
{{ form.csrf_token }}
<fieldset>
{{ form.hidden_tag() }}
<div class="control-group">
<p>Post</p>
<div class="controls">
<p>
{{ form.poster(id='post',class='form-control required ',placeholder="My Post", autocomplete=True , size=3,**{'data-bind': 'value: post'})}}</p>
{% if form.poster.errors %}
<ul class="errors">
{% for error in form.poster.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
<div class="control-group">
<p>postbody<p>
<div class="controls">
<p>{{ form.postbody(id='postbody',class='form-control required ',placeholder="Post Description", autocomplete=True , size=3, **{'data-bind': 'value: postbody'} )}}</p>
</div>
</div>
<div class="control-group">
<p>post url</p>
<div class="controls">
<p>
{{ form.posturl(id='posturl',class='form-control required ',placeholder="My Post", autocomplete=True , size=3, **{'data-bind': 'value: posturl'} )}}</p>
{% if form.posturl.errors %}
<ul class="errors">
{% for error in form.posturl.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
<div class="control-group">
<div class="controls">
<br><input type="submit" id="postit" name="postit" value"poster" class="btn btn-primary" /><br><br>
</div>
</div>
</fieldset>
</form>
<ul data-bind="foreach: posts, visible: posts().length > 0">
<p data-bind="text: post"></p>
<p data-bind="text: postbody"></p>
<p data-bind="text: posturl"></p>
</ul>
<div class="controls">
</div>
{% block tail_script %}
<script src="{{ url_for('static', filename='bootstrap/js/jquery.validate.js') }}"></script>
<script src="{{ url_for('static', filename='bootstrap/js/additional-methods.js') }}"></script>
<script type="text/javascript">
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function Post(data) {
this.post = ko.observable(data.post);
this.postbody = ko.observable(data.postbody);
this.posturl = ko.observable(data.posturl);
}
function PostViewModel() {
var self = this;
self.posts = ko.observableArray([]);
self.post = ko.observable();
self.postbody = ko.observable();
self.posturl = ko.observable();
console.log(self.post)
self.addPost = function() {
self.save();
self.post("");
self.postbody("");
self.posturl("");
};
$.getJSON('/posts', function(postModels) {
var t = $.map(postModels.posts, function(item) {
return new Post(item);
});
self.posts(t);
});
self.save = function() {
return $.ajax({
url: '/post/new',
contentType: 'application/json',
type: 'POST',
data: JSON.stringify({
'post': self.post(),
'postbody': self.postbody(),
'posturl': self.posturl(),
}),
success: function(data) {
console.log("Pushing to post array");
self.posts.push(new Post({ post: data.post, postbody: data.postbody, posturl: data.posturl }));
return;
},
error: function() {
return console.log("Failed");
}
});
};
}
// Activates knockout.js
ko.applyBindings(new PostViewModel());
</script>
{% endblock %}
{% endblock %}
is there any way to run form.validate_on_submit() with request.json['....'] , I am unable to figure where I am going wrong.

Related

HTML wont pass argument to flask missing 1 required positional argument

I can't figure this error out, I am passing the chirp_id from this <a href>
the error TypeError: createCmt() missing 1 required positional argument: 'chirp_id'
The Snippet of the code
{% block content %}
<div class="row">
{% if chirp %}
<h2>{{ chirp[1] }}</h2>
<p>
By : {{ chirp[2] }}
</p>
<p>
{{ chirp[3] }}
</p>
<div>
<a class="btn btn-success" href="{{ url_for('createCmt', chirp_id='{{ chirp[0] }}') }}"> + Comment </a>
</div>
{% else %}
<h3>
Invalid comment
</h3>
{% endif %}
</div>
The URL that is called by the button is this
#app.route('/comment/create', methods=['GET', 'POST'])
def createCmt(chirp_id):
# check if user is logged in
if not session:
return redirect(url_for('login'))
if request.method == 'POST':
data = request.get_json() or {}
if data.get('body'):
user_id = session.get('user_id')
body = data.get('body', '')
body = body.strip()
sql_params = (chirp_id, user_id, body)
conn = db_connection()
cur = conn.cursor()
sql = """
INSERT INTO commentary (chirp_id, user_id, body) VALUES (%d, %d, '%s')
""" % sql_params
cur.execute(sql)
conn.commit()
cur.close()
conn.close()
return jsonify({'status': 200, 'message': 'Success', 'redirect': '/'})
return jsonify({'status': 500, 'message': 'No Data submitted'})
return render_template('comment/create.html')
Does this mean that the chirp_id isn't being passed from the chirp_id='{{ chirp[0] }}'
in the HTML? or I am just stupid
EDIT
this is my create.html that extends to the first HTML
{% extends "comment/form.html" %}
{% block title %}
Create a Comment
{% endblock %}
{% block button %}
<div class="row">
<div class="offset-2 col-6">
<button type="button" class="btn btn-success" name="btnCreate" id="btnCreate" onclick="createCUM()">Create</button>
</div>
</div>
{% endblock %}
and the javascript for getting the body value
function createCUM(chirp_id) {
var body = document.getElementById("body").value;
axios({
method: "POST",
url: "/comment/create/" + chirp_id,
data: {
body: body,
},
headers: {
"Content-Type": "application/json",
}
}).then(
(response) => {
var data = response.data;
if (data.redirect) {
// redirect exists, then set the URL to the redirect
window.location.href = data.redirect;
}
if (data.status == 500) {
alert(data.error);
window.location.href = "/"; // redirect to home page
}
},
)
}
Your #app.route seems to be lacking a paramater, would you like to do it as
#app.route("/comment/create/<chirp_id>", methods = ["GET", "POST"])
Try to change your href to
<a class="btn btn-success" href="{{ url_for('createCmt', chirp_id='{}'.format(chirp[0])) }}"> + Comment </a>
additional edit
I tried to run it I did this
Route for the a href
#app.route("/test")
def testing():
return render_template("testerer.html", chirp_id = 123)
Route for the post
#app.route("/comment/create/<chirp_id>", methods = ["GET", "POST"])
def createCmt(chirp_id):
return f"{chirp_id}"
HTML
<a class="btn btn-success" href="{{ url_for('createCmt', chirp_id='{}'.format(chirp_id) ) }}"> + Comment </a>

How to link to external wepage with form HTML?

The links contained in the form normally display correctly not in the form but in the form every time I click the button I get a forbidden access error. Is the HTML correct? Is there a way around this?
{% for v in owner_obj %}
<div class="container">
<form action="{{ v.Link }}" method="POST" type="submit">
<button style="border: none;">
{% csrf_token %}
<input type="hidden" name="tshirt_id" value="{{ v.id }}" />
<a href="{{ v.Link }}" rel="noopener noreferrer">
<img src="{{ v.Images }}" width="150" height="150">
</a>
</button>
</form>
<figcaption> {{ v.Titles }} </figcaption>
<figcaption> <b>{{ v.Prices }}</b></figcaption>
</div>
{% endfor %}
Added views.py
if request.method == 'POST':
T_shirt.objects.filter(id=request.POST.get('tshirt_id')).update(views=F('views') + 1)
You can't do that if the external website has the validation of csrf_token, because is insecure if anyone is able to do a post to your url from outsite of your website. The only way to do that is if the external website disable the csrf_token validation.
With ajax should be something like this:
<html>
<head>
<script>
$(function () {
$(".counter-button").on("click", function (event) {
event.preventDefault();
var data_id = $(this).attr("data-id");
var url = $(this).attr("href");
$.ajax({
type: "POST",
url: "{{ request.path }}",
data: {
'tshirt_id': data_id
},
success: function () {
window.location.replace(url);
}
});
return false;
});
});
</script>
</head>
<body>
{% for v in owner_obj %}
<div class="container">
<a href="{{ v.Link }}" class="counter-button" data-id="{{ v.id }}">
<img src="{{ v.Images }}" width="150" height="150">
</a>
<figcaption> {{ v.Titles }} </figcaption>
<figcaption> <b>{{ v.Prices }}</b></figcaption>
</div>
{% endfor %}
</body>
</html>
You have to include Jquery before the javascript script.
And then in the added views.py you should do something like this:
import json
from django.http import JsonResponse
def added(request):
if request.method == 'POST':
post_data = json.loads(request.body.decode('UTF-8'))
T_shirt.objects.filter(
id=post_data.get('tshirt_id')
).update(views=F('views') + 1)
return JsonResponse({"message": "success"})
I'm sorry if this doesent work but you might have to put
{{ v.Link }}

multiple html form from a single form model in django

i need your assistance
im building a school president vote tallying system
the vote results are saved in the polls table as
candidate id | pollingstationid | result |
when capturing the results the html page will render the form for each candidate. for example if there are 3 candidates the html form will have 3 forms:
candidate 1:
result _______
candidate id 1001
pollingstationid 301
candidate 2:
result _______
candidate id 1002
pollingstationid 301
candidate 3:
result _______
candidate id 1003
pollingstationid 301
[submit button]
the problem:
when i click submit, its only saving the last form(i.e candidate 3)
how do i get all three entries into the database each as a new row.
views.py
class candidatesview(AjaxFormMixin, View):
form_class = pollsForm
model = Polls
template_name = 'app/candidates.html'
def get(self, request):
form = self.form_class()
candidatesls = Candidates.objects.all()
context = {'title':'polls','form' : form, 'candidates': candidatesls }
#print(context)
return render(request, self.template_name, context )
def post(self, request):
form = pollsForm(request.POST)
candidatesls = Candidates.objects.all()
if form.is_valid():
print(form.cleaned_data['Result'])
print(form.cleaned_data['Candidateid'])
print(form.cleaned_data['PollingstationID'])
form.save()
messages.success(request,('Form submitted successfuly'))
else:
messages.warning(request,('nah!'))
print(messages)
context = {'title':'polls','form' : form, 'candidates': candidatesls, 'message':messages}
return render(request, self.template_name, context)
forms.py
class pollsForm(forms.ModelForm):
class Meta:
model = Polls
fields = ['Result', 'Candidateid','PollingstationID']
html (candidates.html)
{% extends "app/base.html" %}
{% load widget_tweaks %}
{% block content %}
<div class="bg-white">
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-8">
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible show" role="alert">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="false">×</span>
</button>
</div>
{% endfor %}
{% endif%}
<div id="alertbox">
</div>
<div class="form-group">
<form class="my-ajax-form" method="POST" action="{% url 'polls' %}">
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{#{% for field in form.visible_fields %}#}
<table class="table">
{% for candidates in candidates %}
<tr>
<td>
{% render_field form.Result class="form-control" placeholder=candidates.CandidateName id=forloop.counter %}
<input type="number" class="form-control" id={{ forloop.counter }} value={{ candidates.CandidateID }}>
{% render_field form.PollingstationID type="hidden" class="form-control" id="C1_Pollingstation" %}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
</td>
<td>
<div class="circle" style="background:{{ candidates.CandidateColor }}">2</div>
</td>
</tr>
{% endfor %}
</table>
<div class="pull-right">
<input type='submit' class='btn btn-next btn-fill btn-success btn-wd' name='Post' value='Post' />
</div>
</form>
</div>
</div>
</div>
</div>
<br />
{% endblock content %}
{% block javascript %}
<script>
$(document).ready(function(){
var $myForm = $(".my-ajax-form")
var $myMessage = $("#alertbox")
$myForm.submit(function(event){
event.preventDefault()
var $formData = $(this).serialize()
var $endpoint = $myForm.attr("data-url") || window.location.href
console.log($formData)
console.log($endpoint)
$.ajax({
method: "POST",
url: $endpoint,
data: $formData,
success: handleFormSuccess,
error: handleFormError,
})
function handleFormSuccess(data, textStatus, jqXHR){
console.log(data)
console.log(textStatus)
console.log(jqXHR)
$myForm[0].reset();
$myMessage.replaceWith('<div class="alert alert-success show" role="alert" id="alertbox"> post succcess</div> ');
}
function handleFormError(jqXHR, textStatus, errorThrown){
console.log(jqXHR)
console.log(textStatus)
console.log(errorThrown)
$myMessage.replaceWith('<div class="alert alert-warning show" role="alert" id="alertbox"> post failure</div> ');
}
})
})
</script>
{% endblock %}

My Django-ajax Like Button is not working..?

I had tried several times to fix this but not successfull, likes count are all updating when I use the admin panel but not in html template..
views.py
from common.decorators import ajax_required
#ajax_required
#login_required
#require_POST
def like_post(request):
# image_id = get_object_or_404(Post, id=request.POST.get('id'))
image_id = request.POST.get('id')
action = request.POST.get('action')
if image_id and action:
try:
image = Post.objects.get(id=post_id)
if action == 'like':
image.likes.add(request.user)
else:
image.likes.remove(request.user)
return JsonResponse({'status':'ok'})
except:
pass
return JsonResponse({'status':'error'})
post_view.html
{% extends 'base.html' %}
{% load static %}
{% block title %}Users Posts{% endblock %}
{% block content %}
<div class="container-fluid">
<form method="post" enctype="multipart/form-data">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Post">
</form>
</div>
{% for post in posts %}
<div class="w3-container w3-card w3-white w3-round w3-margin"><br>
<img src="{% if post.user.profile.photo %} {{post.user.profile.photo.url}}
{% else %}{% static 'img/user.png' %}{% endif %}" alt="Avatar" class="w3-left w3-circle w3-margin-right" style="width:60px">
<span class="w3-right w3-opacity">{{ post.created }}</span>
<h4>{{ post.user|title }}</h4><br>
<hr class="w3-clear">
<p>{{ post.title }}</p>
{% if post.image %}
<div style="max-width:100%;height:auto;object-fit: cover;" class="img-fluid">
<img src="{{ post.image.url }}" class="img-fluid" style="max-width:100%;height:auto;object-fit: cover;">
</div>
<p>{{ post.description }}</p>
{% endif %}
{% with total_likes=post.likes.count users_like=post.likes.all %}
<div class="image-info">
<div>
<span class="count">
<span class="total">{{ total_likes }}</span>
like{{ total_likes|pluralize }}
</span>
<a href="#" data-id="{{ post.id }}" data-action="{% if request.user in users_like %}un{% endif %}like" class="like button mb-3">
{% if request.user not in users_like %}
Like
{% else %}
Unlike
{% endif %}
</a>
</div>
</div>
{% endwith %}
</div>
{% endfor %}
{% include 'post/pagination.html' with page=posts %}
{% endblock %}
{% block domready %}
$('a.like').click(function(e){
e.preventDefault();
$.post('{% url "post:like" %}',
{
id: $(this).data('id'),
action: $(this).data('action')
},
function(data){
if (data['status'] == 'ok')
{
var previous_action = $('a.like').data('action');
// toggle data-action
$('a.like').data('action', previous_action == 'like' ?
'unlike' : 'like');
// toggle link text
$('a.like').text(previous_action == 'like' ? 'Unlike' :
'Like');
// update total likes
var previous_likes = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'like' ?
previous_likes + 1 : previous_likes - 1);
}
}
);
});
{% endblock %}
base.html
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/js.cookie.min.js' %}"></script>
<script>
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$(document).ready(function(){
{% block domready %}
{% endblock %}
});
</script>
urls.py
from django.urls import path
from post import views
from django.conf import settings
from django.conf.urls.static import static
app_name = 'post'
urlpatterns = [
path('',views.post_list,name='post_list_view'),
path('like/',views.like_post,name='like'),
]
This the entire code when I tried to modify the ajax function the like button changes and then it will change all other likes present in the post_view.html, where it contains the all other posts in the same page..

jQuery html() to replace div contents works only for the first time

I'm using an AJAX request to handle some part of my app that deals with managing photos...the user can click on a '<' or '>' button to change the ordering of the photos. All works well, but only for the first time I click the button...subsequent clicks do not trigger anything.
Main template:
<script type="text/javascript">
$(function() {
$(".manage_photo").click(function(event) {
event.preventDefault();
var id = $(this).attr("id");
var action = $(this).attr("name");
var data = { id: id, action: action };
$.ajax({
type: "POST",
url: "{% url managePhotos %}",
data: data,
success: function(results) {
$("#list").html(results);
},
});
})
})
</script>
....
{% if photos %}
<p><strong>{{ photos.count }} photo(s) added</strong></p>
<div class="highslide-gallery">
<div id="list">
{% include "ajax/photos.html" %}
</div>
</div>
<div class="cleaner"></div>
{% else %}
<h5>Photos not yet added</h5>
{% endif %}
Code for ajax/photos.html:
{% for photo in photos %}
<div class="vehicle_photo">
<button class="manage_photo" name="incr" id="{{ photo.id }}"
{% if forloop.first %} disabled="disabled"{%endif %} style="float: left">
<
</button>
<button class="manage_photo" name="decr" id="{{ photo.id }}"
style="float: right">
>
</button>
<br />
<a href="{{ photo.original_image.url }}" class="highslide"
onclick="return hs.expand(this)">
<img class="ui-corner-all" src="{{ photo.thumbnail_image.url }}" />
</a>
<br />
{{ photo.position_number }}
</div>
{% endfor %}
My view returns a render_to_response version of photos.html after changing the ordering for the selected photo, with results containing the queryset for all photos in that photo's set, and a status message ie. success, failed:
return render_to_response('ajax/photos.html', results)
What could be my issue? I tried the suggestions at: this SO question, but none work out for me. Any insight would be very much appreciated since I've been at this since yesterday.
when you do the $(function...) things that are in the DOM get bound, but when you replace stuff with other stuff, the new stuff is not bound. You could use the .live command to make it work for old and new stuff, or you could bind the new stuff again (run the $(".manage_photo").click(...) again after the ajax.
BTW, you could replace the block of ajax with a simple $("#list").load("{% url managePhotos %}")