I have been stuck on this error for some time and I can't wrap my head around the problem or what it even means.
I found some answers but none really solved my issue.
Here is a brief desciption of what I do:
In Javascript, I call this function with an int as a parameter such as:
function follow (user_id) {
// retrieves post for current selection
fetch(`/follow/${user_id}`, {
method: 'PUT',
body: JSON.stringify({
follow: true
})
})
}
My url path, from url.py, is as follow:
path('follow/<int:user_id>', views.follow, name="follow")
finally, in views.py, this function is called:
def follow(request, user_id):
user = User.objects.get(id = user_id)
if request.method == "PUT":
data = json.loads(request.body)
if data.get("follow") is not None:
followed = Followed(
user_id = user.id,
followed_by_id = request.user,
)
followed.save()
return HttpResponseRedirect(reverse("index"))
else:
return HttpResponseRedirect(reverse("index"))
I have tried a few different approaches such as removing the .value but I keep getting the following error:
Field 'id' expected a number but got <SimpleLazyObject: <User: username>>
I check along the way and the ID is an int all the way until it is passed to the model to be saved.
I am using the abstractUser model.
Let me know if more information is needed.
Kind regards,
Related
After using the below to pull data from Dynamo db sucessfully
async function pullone(sessionid) {
const params = {
TableName: dynamodbTableName,
Key: {
'sessionid': sessionid
}
};
return await dynamodb.get(params).promise().then((response) => {
return response.Item
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
});
}
Instead of 'return response.Item' i just want to return the count instead.
I tried doing count(pullone(sessionid)) but not sure if that is even a valid method. Please assist
Not sure if I understood your question, but:
Since you're requesting data associated with a primary key, you'll get either 0 or 1 element in Item.
So, if you aim to know if "you've found something or not", you can use Number(response.Item != null) and you'll get 1 in case of "something" and 0 in case of "nothing".
If, instead, your data contains a "count" attribute, then (await pullone(sessionId)).count should work.
Otherwise, you have to query your DB (but you'll get Items (plural) in your response) and use the length() function of the Items array you'll get in the response.
My issue is that whenever the button const loadOldPlayer is clicked, it sends two GET requests, as shown in the screenshot below. What this results in is the wrong template being rendered (showsPlayer.html should be what is rendered but instead it just renders playerView.html). I can't figure out why this is happening, so any help is appreciated. Below the screenshot is my code.
let playerName
const loadOldPlayer = document.getElementById('playerLoader');
const enterProfile = (usedToLoad) => {
console.log(playerName)
if (usedToLoad) {
playerName = document.getElementById('loadPlayerName').value
};
const playerData = {
playerName: playerName
};
const JSONdata = JSON.stringify(playerData);
fetch(`/profile?tags=${JSONdata}`, { method: "GET" }).then((response) => {
if (response.ok) {
document.getElementById('loaderLabel').innerHTML = "Loading Player"
}
else {
alert("Something bad happened.");
};
});
};
loadOldPlayer.addEventListener("click", enterProfile.bind(true));
from flask import Flask, render_template, request
from static.SNEKfiles import SpaceShipGame
import json
game_app = Flask(__name__)
#game_app.route('/')
#game_app.route('/home')
def home():
return render_template("HTMLPage1.html")
#game_app.route('/profile', methods=['GET'])
def profile():
if request.method == 'GET':
playerName = request.args.get('tags')
if playerName != None:
print("got the name")
return render_template("showsPlayer.html")
else:
print("here is issue")
return render_template("playerView.html")
if __name__== "__main__":
game_app.run(debug=True, host='127.0.0.1', port=7777)
Yes my HTML files are badly named, I'll probably get around to fixing that. Eventually.
I'm inexperienced with this, so I might be completely wrong here. Anyway, try adding the event listener with
loadOldPlayer.addEventListener("click", function() {
enterProfile(true);
});
instead of
loadOldPlayer.addEventListener("click", enterProfile.bind(true));
I think the bind(true) might be causing the empty querystring.
If this doesn't work, could you add some debug output?
Also, the return render_template("showsPlayer.html") successfully returns the html, but the client never actually uses it. Try using
fetch(`/profile?tags=${JSONdata}`, { method: "GET" }).then((response) => {
if (response.ok) {
document.getElementById('loaderLabel').innerHTML = "Loading Player"
return response.text()
}
else {
alert("Something bad happened.");
}
}).then((html) => {
console.log(html) // should show response html
document.open();
document.write(html); // writes response html to body
document.close();
})
Document.write() is considered bad practice, but it is the only way (that I know of, at least) to dynamically replace the entire page.
I edited this answer because I didn't notice your use of the .bind(true) earlier.
The event listener expects a function reference, which is what Quackers had you implement. Similar to Quackers solution, but using the shorter arrow function form :
loadOldPlayer.addEventListener("click", () => enterProfile(true));
That way, you are passing a function reference, and that function, when called by the event, just call your function with the value set to "true" as you expect.
Your original code was using .bind() which creates a new function with this set to the value you provided to .bind. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind.
By passing enterProfile.bind(true) to addEventListener, you ended up passing a new enterProfile function to handle the click event (that new function having the this set to true, which had no effect for you).
When the event fired, the browser actually was passing the Event object to the function, not the value true (see event callbacks https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_event_listener_callback).
At that point, the if (usedToLoad) was entirely dependant on what Event data was passed and if that evaluated to a truthy value or not.
Im working on a Django project kind of network. I have a JS code in which with a fetch-PUT i update my db and i can check from the file that it is updated.
function update_like(identity) {
fetch('/like',{
method: 'PUT',
body: JSON.stringify({
id: identity,
})
},
show(identity)
)
};
And then with a fetch-GET i try to retrieve the data
function show(identity) {
fetch('/like', {
headers: {
'Cache-Control': 'no-cache'
}
})
.then(response => response.json())
.then(likedic => {
console.log(likedic);
if (likedic[identity]){
document.getElementById(`arithmos${identity}`).innerHTML = ` ${likedic[identity].length}`;
} else {
document.getElementById(`arithmos${identity}`).innerHTML =' 0';
}
});
}
the thing is, that every time, it displays the data from the just previous updated db.
I mean first time i run update_like function, the show function diplays the db as it was before update_like function runs. But i can see from the file that db is updated.
Second time i run update_like function the show function diplays the db as it should be the first time, even if i can see again from the file that db is updated etc.
I suppose that it doesn't have enough time to read the update db. I have tryied so many things but i cant make it work. Underneath is my python function
def like(request):
likedic = {}
if request.method == 'GET':
allcomments = Like.objects.all()
for i in range(len(allcomments)):
if allcomments[i].comment.id not in likedic.keys():
likedic[allcomments[i].comment.id] = []
likedic[allcomments[i].comment.id].append(allcomments[i].user.username)
print('likedic',likedic)
else:
likedic[allcomments[i].comment.id].append(allcomments[i].user.username)
return JsonResponse(likedic, safe=False)
elif request.method == "PUT":
data = json.loads(request.body)
Likes = Like.objects.filter(comment = Comment.objects.get(id = data['id']), user = User.objects.get(username = request.user.username))
if Likes:
Likes.delete()
else:
Likes = Like(comment = Comment.objects.get(id = data['id']), user = User.objects.get(username = request.user.username))
Likes.save()
return HttpResponse(status=204)
# Email must be via GET or PUT
else:
return JsonResponse({
"error": "GET or PUT request required."
}, status=400)
I would really apreciate some advise. Thanks so much in advance.
Use async functions instead of regular functions, and await the completion of the first function before performing the 2nd. For example, convert update_like to an async funciton.
Later, call show only after awaiting update_like:
// `await` must be used within an async fucntion
// So, I'll use await inside this immediately invoked function:
(async function()
{
let identity = "someIdentity";
await update_like(identity); // Waits until update is complete
return show(identity);
})();
I finally found a solution! I added a setTimeout function before I call show function. I set 0.05sec and it works! I dont know if this is the right or the best way to do it but it finally works!
function update_like(identity) {
fetch('/like',{
method: 'PUT',
body: JSON.stringify({
id: identity,
})
},
setTimeout(() => {
show(identity);
}, 50)
)
};
Im trying to sign a BlockCypher transaction on the bitcoin testnet using bitcoinjs as described here but I keep getting the error:
{"error": "Couldn't deserialize request: invalid character 'x' in literal true (expecting 'r')"}
I have searched around and can find no documentation on what the problem is. Below is the code im using to try and sign the transaction.
var bitcoin = require("bitcoinjs-lib");
var buffer = require('buffer');
var keys = new bitcoin.ECPair.fromWIF('cMvPQZiG5mLARSjxbBwMxKwzhTHaxgpTsXB6ymx7SGAeYUqF8HAT', bitcoin.networks.testnet);
const publicKey = keys.publicKey;
console.log(keys.publicKey.toString("hex"));
var newtx = {
inputs: [{addresses: ['ms9ySK54aEC2ykDviet9jo4GZE6GxEZMzf']}],
outputs: [{addresses: ['msWccFYm5PPCn6TNPbNEnprA4hydPGadBN'], value: 1000}]
};
// calling the new endpoint, same as above
$.post('https://api.blockcypher.com/v1/btc/test3/txs/new', JSON.stringify(newtx))
.then(function(tmptx) {
// signing each of the hex-encoded string required to finalize the transaction
tmptx.pubkeys = [];
tmptx.signatures = tmptx.tosign.map(function(tosign, n) {
tmptx.pubkeys.push(keys.publicKey.toString("hex"));
return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex");
});
// sending back the transaction with all the signatures to broadcast
$.post('https://api.blockcypher.com/v1/btc/test3/txs/send', tmptx).then(function(finaltx) {
console.log(finaltx);
}).catch(function (response) {
console.log(response.responseText);
});
}).catch(function (response) {
console.log(response.responseText);
});
It seems this line return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex"); is the problem but im not sure on what is wrong.
This question was discussed and answered here. This post and this one are to be looked into in particular.
As far as I understand, according to the issue respective one was opened at BlockCypher repo. Although its status is still opened till this date, current BlockCypher JS docs respective API description contains altered version of the line
return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex");
with toDER() conversion prior to toString(), consequently it looks like this now
return keys.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex");
So this post gives an answer to how to send a post for downloading a file using forms. But my API endpoint isn't recognizing the form data.
[HttpPost]
public async Task<IHttpActionResult> DownloadPdfs([FromBody] IEnumerable<int> ids)
{
if (ids == null || ids.Count() < 1)
{
return BadRequest("No ids supplied.");
}
...
'ids' always has a count of 0.
Here's the JS code:
function downloadFile(ids) {
var win = 'w' + Math.floor(Math.random() * 1000000000000);
window.open('', win, 'width=250, height=100');
var f = $('<form></form>')
.attr({ target: win, method: 'post', action: 'api/pdfs' })
.appendTo(document.body);
_.each(ids, function (id) {
$('<input></input>')
.attr({ type: 'hidden', name: 'ids', value: id })
.appendTo(f);
});
f[0].submit();
f.remove();
}
Initially, I just had it the same as the other linked answer which was just one input appended to the form, in which I set the value to 'ids'. I tried this next, but that still didn't work.
Does anyone know how to adapt this to still use post data to provide my ids, which are needed to create and supply the downloaded file? Or is there a better way to do this?
I've tried doing it just using Ajax, which returns the file content in the responseText, but I can't make use of it in there and I can't get the browser to open it.
Edit 1
I also just tried setting the value to this:
value: '{ids: [' + ids.toString() + ']}'
That didn't work.
Edit 2
Just tried changing the endpoint parameter to this:
([FromBody] int[] ids)
...to no avail.