Flask url_for stop accepting double-digit user IDs. BUG? - python

I am relatively new to Flask and I could not figure out what is the problem with my function nor I could find that someone had had the same problem. It is even difficult to explain.
Template url_for link:
<a href="{{ url_for('view_post', pc=post.product_category_by.product_cat_name, post_id=post.id, ui=post.author_id) }}">
Flask view function: (Flask SQLAlchemy. PostgreSQL)
#app.route('/viewref/<pc>/<int:post_id><int:ui>')
def view_post(pc, post_id, ui):
post = db.session.query(Post).filter_by(id=post_id).first()
db.session.commit()
gc.collect()
return render_template('view_post.html', post=post)
Example:
Lets take a post with ID 26 and two users (or authors of post) with IDs 9 and 10. When I pass a user with ID 9, I get redirected to the correct view with the end url: /viewref/productCat/269 (26 is post id and 9 is user id). Great, it works and I see a post!
The problem:
But when a user with ID 10 or higher (12, 299 etc.) get passed in the url_for, the query of view_post function pulls None from the database, subsequently my view_post.html template throws an Error
(UndefinedError: 'None' has no attribute 'product_category_by')
What is the connection?
The key of the view_post function is only to fetch a post by a given post_id. Why does it get None in the cases where user ID > 9, if my function takes only post_id for the query and other variables are used for the url construction only?
P.S. It all works fine if I exclude ui from the url_for and view_post function.

I'm not sure how you're expecting the URL router to tell where post_id ends and ui starts. You should use an actual separator:
#app.route('/viewref/<pc>/<int:post_id>/<int:ui>')

I think you should change your URL scheme. What if the user id is 12 and the post_id is 34? In your URL it would be concatenated to 1234. How can we tell this apart from post_id: 1, user_id: 234 versus post_id: 123, user_id: 4?

Related

Get request with django returns None for the user

I'm trying to get the details of the user who makes a get request in django. I'm using postman to perform the get request but when I try to print request.user and type(request.user):
#In the view
class SomeView(APIView):
....
....
def get(self, request, pk, format=None):
print(f'request: {request.user}, {type(request.user)')
I get None and None for the user and the type.
I've looked though many stackoverflow posts but I'm struggling finding out the reason.
From:
Django username is empty in a GET request
https://www.django-rest-framework.org/api-guide/authentication/
I thought perhaps I'm not performing the get request with a user, but if that is the case, I should be getting an Anonymous object as the type for user right? But instead it's telling me it's None
I should mention from postman I'm under the Authorization tab, I've tried using a Bearer Token which I know I had the correct token as well as (separately) using basic auth by having the username and the password. Either method results in request.user being None.
If I just print out request I get:
<rest_framework.request.Request: GET '/test/number/33574677/'>,
I'm not sure what the issue here is, does it have something to do with the way I'm using postman to send the request? Or perhaps I'm missing something very trivial? Thank you.

Python Flask Button to get Unique values

I am trying to get a list sets of information :
Name:
Date:
Status:
It will be displayed in the HTML page so e.g
Name: John
Date: 11 January 2018
Status: Pending
Name: Alex
Date: 10 January 2018
Status: Pending
There will be a button for each of the above data named 'Confirm'.
How do I go about so that when I click the 'Confirm' button on one of the data above, it will only process and make use of that data?
e.g if I click the button on Name : Alex, it will only get the info of Alex.
How do I go about doing this in Python Flask?
I can do a POST but how do I capture that the data being sent is from that specific set?
Please give me some suggestions.
Thank you
Use Identities
Information that is stored on a computer has to be identified through a means somehow. This can be done with an index such as an incrementing index, a GUID, a SHA hash or some other kind of random generator that can create an random id. The random id can then be given a 'purpose' to represent that data.
I'm not sure how you have implemented this in Flask. Whether this is done with
some kind of SQL driver, a JSON/XML object, or whether this is written in plain text. However, the place to start is how you're storing your data so that you can figure out the best way to use it.
Use of Payloads
Payloads are basically where you can give or send all data rather than metadata or identities. This could allow you to identify or change the information before it is stored or sent. However this is normally done to upload/download and change data with an API rather than used to identify data as it would take longer to process.
Solution
The best one out of the two would be to use identification. The implementation could be as simple as visiting a link that contains an ID that (REST) API's would typically use (e.g. /statuses/1 or /statuses/321THISISUNIQUE).
You could create a form that contains that id as part of a value such as:
<form action='/statuses' method='POST'>
<input type='hidden' name='id' value='321THISISUNIQUE'/>
<input class='confirm' type='submit' value='confirm'/>
</form>
Example to get a status using an id
#app.route('/statuses/<id>')
def getStatus(id):
return 'Status for %s' % id
Example to use POST with an id (Refer to Flask - the request object)
#app.route('/statuses', methods=['POST'])
def changeStatus():
# Technically this should be a PUT request as part of REST
id = request.args.id
return 'Change status with id %s' % id
Using flask-sqlalchemy would make it easy for you. Then you can retreive all data from database, and when user click the button you will call a view function which will take Name or you can change to the person id.
db = SQLAlchemy(app)
class Person(db.Model):
Name = db.Column(db.String)
Date = db.Column(db.DateTime)
Status = db.Column(db.String)
#app.route('/')
def index():
persons = Person.query.all()
return render_template('index.html', persons=persons)
#app.route('person-info/<name>')
def person_info(name):
person = Person.query.filter_by(Name=name).first()
return render_template('person.html', person=person)
#index.html
{% for person in persons %}
...
<a href="{{ url_for('person_info', name=person.Name)}}">
{% endfor %}
#person.html
{{person.Name}}{{person.Status}}{{person.Date}}

Pass variable from jinja2 template to python

Sorry if this is a noob question I am still learning. I have passed a variable from python code to a jinja2 HTML template to set up a URL, like this:
Delete
When this link is pressed it should run a query that deletes the entity with that ID. But when the link is pressed it goes to /delete/1827424298 for example, which results in a 404 error as the request handler doesn't exist.
I need to pass that ID back into my python code so it can run a method to delete the entity with that same ID. How do I go about doing this? Using webapp2 if that is important.
class DeleteRequestHandler(webapp2.RequestHandler):
def get():
template = template_env.get_template('myrequests.html')
context = {
'results': results.key.id()
}
self.response.out.write(template.render(context))
EDIT: I've added my delete handler - it is incomplete as I have yet to add the query to delete the entity. My thinking behind it so far is I can grab the results.key.id() from the jinja2 template and put it into results but I am not sure if this would work.
So I think what you're confused about is how to set up a route handler with a dynamic part to the URL. It's a shame that this is completely skipped over in the webapp2 tutorial, as it's a fundamental part of writing any web application. However, it is covered well in the guide to routing, which you should read.
At its simplest, it's just a matter of putting a regex in the route:
app = webapp2.WSGIApplication([
...
(r'/delete/(\d+)', MyDeleteHandler),
])
which will now route any URL of the form /delete/<number>/ to your deletion handler.
The ID that you pass in the URL will be the first positional argument to the handler method:
class MyDeleteHandler:
def get(self, item_id):
key = ndb.Key(MyModel, item_id) # or whatever

Issues sending and receiving a GET request using Flask

I'm having issues with correctly sending and receiving a variable with a GET request. I cannot find any information online either. From the HTML form below, you can see I'm sending the value of 'question' but I'm also receiving 'topic' from a radio button in the form (though the code is for that is not below).
I want to send 'topic' using POST but use GET for 'question'. I'm aware that the form method is POST though I'm not sure how to cater for both POST and GET.
HTML Form:
<form method="POST" action="{{ url_for('topic', question=1) }}">
My second issue is that I'm unsure how to receive 'topic' AND 'question' from the form. I've managed to receive 'topic' as seen below but I'm not quite sure how to receive 'question'. Preferably it would be better for the URL to be like so:
www.website.com/topic/SomeTopic?question=1
For the code below, I found online that request.args[] is used for receiving GET requests though I'm not sure if it is correct.
Flask:
#app.route('/topic/<topic>', methods=['POST', 'GET'])
def questions(topic):
question = request.args['questions']
return render_template('page.html')
The question is
How do I send two variables from a form using GET and POST for different variables at the same time.
How would I go about receiving both variables?
The short answer to your question is that you can't send both GET and POST using the same form.
But if you want your url to look like you specified:
www.website.com/topic/SomeTopic?question=1
then you're almost there. First you will need to already know the name of the topic as you have to specify that in your call to url_for() for the questions url.
<form method="GET" action="{{ url_for('questions', topic_name="cars") }}">
# Your url will be generated as www.website.com/topic/cars
flask
# Note that I changed the variable name here so you can see how
# its related to what's passed into url_for
#app.route('/topic/<topic_name>')
def questions(topic_name):
question = request.args['question']
return render_template('page.html')
Now when you submit your form, your input will be sent as a GET, an asumming you have an input field with the name question you'll be able to get the value of that field.

Difficulty having Django find database user

I'm writing a web app which has a page for admin tasks. One of the tasks is that the admin users must be able to edit other users details. Alas, I've fallen at quite a simple roadblock.
I've set up a very simple jQuery AJAX Get request, successfully transferring a string to the server and back. This is just background, but not the issue. The issue lies in retrieving other user's objects.
At the moment, with a username I know exists, this code which is accessed in views.py, produces a 500 Internal Server Error.
#login_required
def user_edit_getuser(request):
# Like before, get the request's context.
context = RequestContext(request)
inputname = request.GET['inputNameSend']
user_obj = User.objects.get(inputname)
return HttpResponse(inputname) #later will return a JSON String
get takes keyword arguments only: the key is the field to look up.
user_obj = User.objects.get(username=inputname)
Also, you should probably deal with the possibility that the GET request has no inputNameSend key.
For JS development, you can usually see the error page in the Chrome dev tools/Firebug console in the Network tab.

Categories