I am experiencing a weird issue using Django on Google App Engine. I have a file upload form defined within a django-app like this:
class ConvertForm(forms.Form):
from = forms.ChoiceField(choices=choices_from,
label='from:')
to = forms.ChoiceField(choices=choices_to,
label='to:')
class Meta:
fields = ('from','to')
And then I have in my app.views file the following:
def convert(request):
if request.POST:
form = ConvertForm(request.POST,request.FILES)
if form.is_valid():
from = form.cleaned_data['from']
to = form.cleaned_data['to']
# Redirect to a result page after post to avoid duplicates
return HttpResponseRedirect('/convert/results')
else:
form = ConvertForm()
args = {}
args.update(csrf(request))
args['form']=form
return render_to_response('convert.html',args)
The form-part of my convert.html template looks like this:
<form action="/convert/convert/" method="post" enctype="multipart/form-data">{%\
csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" name="submit" value="Convert">
</form>
It's supposed to be a file-upload form (hence the multipart), but I edited the form-contents for brevity.
Now, when I browse the proper url, nothing happens. I can clearly see that the correct functions are being called, since replacing the body of the convert() function with a simple
return render_to_response('convert_test.html',{'some_text':some_text})
displays the value of some_text in the browser window. Is there any additional quirks when dealing with forms within GAE that I am missing, or why isn't convert.html being rendered with the form? I should mention that all of this is on localhost, I haven't deployed it yet.
Edit: After some more fiddling around with this, it seems that maybe the source of the error is in the inheritance of templates. If I take out all django-tags {} in the convert.html, I can get the form to render correctly.
So, the question is now how do I properly set up template inheritance within GAE?
My full convert.html template looks like this:
{% extends "base.html" %}
{% block content %}
<h2>[ convert ]</h2>
<form action="/convert/convert/" method="post" enctype="multipart/form-data">{% \
csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" name="submit" value="Convert">
</form>
{% endblock %}
So basically redefining the content block of the base.html template. This was working perfectly before I tested it on GAE, so I can't shake the feeling that's involved somehow.
If it is relevant, my django settings.py looks like this for the templates:
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__),'..','convert','templates'),
os.path.join(os.path.dirname(__file__),'..','templates'),
)
And as I said, taking out the {}-tags from convert.html gives me the form, but rendered on its own in an otherwise completely white and empty page.
This is the contents of my base.html template
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/\
DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="Your description goes here" />
<meta name="keywords" content="your,keywords,goes,here" />
<meta name="author" content="Your Name" />
<link rel="stylesheet" type="text/css" href="/static/css/basic-minimal.css" ti\
tle="Basic Minimal" media="all" />
<title>Basic Minimal v1.2</title>
</head>
<body class="light">
<div id="wrap">
<div id="header">
<h1>[ snazzy title ]</h1>
</div>
<div id="sidebar">
<ul>
<li>[ Convert ]</li>
<li>[ Transform ]</li>
<li>[ Help ]</li>
<li>[ References ]</li>
</ul>
</div>
<div id="content">
<h2>[ more title ]</h2>
<p>Text</p>
<p>More text</p>
</div>
</div>
</body>
</html>
This works beautifully for the "title" page (even the css gets loaded), but rendering other templates as convert.html above using this as a base does not work.
Related
I am ordering the query result using time but I want to give the user the ability to choose the way he wants to order data lets say he wants to use alphabetical order or he wants to order with ascending or descending order I want to know how to that in flask, sorry for my bad English
this is my code
#routes.route('/posts')
def show_posts():
page=request.args.get('page',1,type=int)
posts=Posts.query.order_by(Posts.timestamp.desc).paginate(page,per_page=10)
return render_template('routes/show_posts.html',posts=posts)
ok, so this is my first flask answer (I only yesterday finished tutorials):
EDIT/INFO: at the end I didn't use any forms to accomplish this, just simple routes, but forms could be used too, this just seemed a bit more simple (more because I couldn't figure out how to use those forms for this :))
EDIT2/INFO: also I don't think for this particular code there is any need for that methods argument in decorators so that could probably be removed for this specific code
the main file (it contains everything because that was easier than to show each module I would have used)
from flask import Flask, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
#app.route('/posts/filter_by/<string:key>')
#app.route('/posts', methods=['GET', 'POST'])
#app.route('/')
def all_posts(key=None):
posts = Post.query.order_by(Post.title.asc()).all()
if key == 'ZA':
posts = Post.query.order_by(Post.title.desc()).all()
return render_template('posts.html', posts=posts)
if __name__ == '__main__':
app.run(debug=True)
and here is the template (uses bootstrap stuff):
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle"
type="button" id="dropdownMenu1" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Sort by
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
<a class="dropdown-item" href="{{ url_for('all_posts', key='AZ') }}">A-Z</a>
<a class="dropdown-item" href="{{ url_for('all_posts', key='ZA') }}">Z-A</a>
</div>
</div>
{% for post in posts %}
<div class="card">
<div class="card-body">
<h4 class="card-title">{{ post.title }}</h4>
<p class="card-text">{{ post.content }}</p>
</div>
</div>
{% endfor %}
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
So the first thing (top-down):
import all that is needed
then initialize the Flask and SQLAlchemy classes and also config the app to the database
Create the post model for storing posts and stuff (that I don't exactly know)
So then comes the main part - the route.
So first of I create a route with a variable:
#app.route('/posts/filter_by/<string:key>')
this will allow to request this URL and be able to get additional information (from that variable) that will help with handling the response
then add more routes so that the url looks cleaner and that is pretty much the only reason (as far as I know)
then define the function:
name it what You feel like but You have to pass the variable as an argument and since multiple routes are used and probably for other reasons too set a default value for that argument so that it is not necessary to be provided
then using simple if statements and using that variable handle how posts are ordered
then return the template including those posts in that order
Now about the template
First of it uses bootstrap stuff and I got the most code from there (just copy pasted from their website) or here which is a nice cheatsheet.
So I copied the dropdown menu from that cheatsheet and just changed some values, most notably the href attribute:
Those I replaced with url_for functions and passed the variable too as You can see so that the request sent is with that variable that will allow to handle how posts are ordered
Hope all is clear, if You have any more questions, ask them.
first thing first Matiiss your answer is very good thanks for the help, now I have found another way it has some similarities to Matiiss answer i want to share it so if anyone found this question now you have two answers to choose from.
#routes.route('/posts')
def show_posts():
posts= Posts.query.order_by(Posts.name.desc()).all()
filter_rule = request.args.get('filter')
if filter_rule == 'A-Z':
posts= Posts.query.order_by(Posts.name).all()
return render_template('posts.html',posts=posts)
HTML part
<div class="row">
<div class="col-md-3">
<div class="nav nav-pills flex-column" role="tablist" aria-orientation="vertical">
<a class="nav-item nav-link"
href="{{ url_for('.show_posts', filter='A-Z') }}">
A-Z
</a>
<a class="nav-item nav-link"
href="{{ url_for('.show_posts', filter='Z-A') }}">
Z-A
</a>
</div>
</div>
I tried to reset password using Ajax in Django.For that, firstly I took email id from input box using a function and send it to views.py file using Ajax.In views.py file,there is a code for receiving email-id using GET method and check whether the email-id is available or not in the table.If available send the email-id back to html file using HttpResponse and display it using alert function.But it does not work properly.Can anyone suggest a solution for this.
HTML file :
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<title>Index Page</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="{% static 'styles/style.css' %}" rel="stylesheet"/>
<script>
function getpass(){
let username=$("#uname").val()
$.ajax({
url : "{% url 'passwordreset' %}",
type : "GET",
data : {username : username},
success :function(data){
alert(data);
}
})
}
</script>
</head>
<body>
<section class="sflog" id="sflog">
<div class="container-fluid">
<div class="row">
<div class="col-12" id="std">
<form method="GET" action="">
{%csrf_token%}
<center>
<h3>Password <span>Reset</span></h3><br><br>
</center>
<div id="result"></div>
<label style="color:white;padding-left:13%;">Enter Your Username</label>
<center>
<input type="text" id="uname" name="username" placeholder="Username" required><br>
</center>
<button type="submit" style="margin-left:12%;" onclick="getpass()" name="login">Submit</button><br><br><br><br>
</form>
</div>
</div>
</div>
</section>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
urls.py
from django.urls import path
from . import views
urlpatterns=[
path('User/Forgot_Password',views.user_forgot_password,name="ufpassword"),
path('User/Forgot_Password/Reset',views.user_forgot_password_reset,name="passwordreset"),
]
views.py
from django.shortcuts import render,redirect,get_object_or_404
from user.models import clientlogin
from django.http import HttpResponse
def user_forgot_password(request):
return render(request,"forgot_password.html")
def user_forgot_password_reset(request):
if request.method == 'GET':
un = request.GET.get('username')
print(un)
try:
user = get_object_or_404(clientlogin, Username=un)
return HttpResponse(user.Username)
except:
return HttpResponse("No user registered with this Email ID")
else:
return render(request, "forgot_password.html")
First change the order in urls
urlpatterns=[
path('User/Forgot_Password',views.user_forgot_password,name="ufpassword"),
path('User/Forgot_Password/Reset',views.user_forgot_password_reset,name="passwordreset")
]
Because when request arrives, it will match the first always so either edit it to be
re_path('User/Forgot_Password$',views.user_forgot_password,name="ufpassword")
This way your reset URL won't match the forget password.
As some said put JQuery before $ sign.
I am trying to get input from a html form in django , python code below:
def add(request):
n = request.POST.get('Username', 'Did not work')
i = Item(name=n,price=0)
i.save()
return render(request,'tarkovdb/test.html')
Second pic is my html code:
<html>
<head>
<meta charset="UTF-8"›
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384—Vkoo8x4CGs0 OPaXtkKtu6ug5T0eNV6gBiFeWPGFN9Muh0f23Q9Ifjh" crossorigin="anonymous">
<title>Tarkov Database Web App</title>
</head>
<body>
<h1>This is the page to add items</h1>
<li>List of Items in DataBase</li>
<form>
<div class="form—group">
<label for&username'> Username: </lable>
<input type&text' name='Username' id.'username'> <br><br>
</div>
<button type="submit" class="btn btn—primary">Submit</button>
</form>
You need to set your method attribute to "post" on your HTML form tag. Like this:
<form method="post">
<!-- your fields here -->
</form>
Otherwise you'll be sending a GET request, which is the default value of the method attribute.
PD.: Please paste your code, make it easy for the community to help you. Otherwise you'll get down voted.
Ok so I am new to flask, and want to know what objects or tools I would use to do this. I want to create a form, where the user inputs some text, clicks a submit button, then the text that they submitted is bound as a python string, and has a function run on it, and that text is then posted back onto the web page they are viewing with the return value of that function it went through. Here is an example:
html form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action = "/" method="get">
<input type="text" name="mail" size="25">
<input type="submit" value="Submit">
</form>
<textarea cols="50" rows="4" name="result"></textarea>
</body>
</html>
Then here is what I believe should be the url function should look like
#app.route('/', methods=['GET', 'POST'])
def form():
if request.method == 'GET':
input_text = request.data #step to bind form text to python string
new_text = textfunction(input_text) #running the function on the retrieved test.
return (new_text) # no idea if this is write, but returns text after modification.
What would be the best way to set this up? Would it be correct to put a variable as the value for the input html? Need some help on this.
Basically, what you want to do is have a block in your template that is only included if the variable has a value set. See the following example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action = "/" method="get">
<input type="text" name="mail" size="25">
<input type="submit" value="Submit">
</form>
{% if result %}
<textarea cols="50" rows="4" name="result">{{ result }}</textarea>
{% endif %}
</body>
</html>
and then in your python code
#app.route('/', methods=['GET', 'POST'])
def index(result=None):
if request.args.get('mail', None):
result = process_text(request.args['mail'])
return render_template('index.html', result=result)
def process_text(text):
return "FOO" + text
I am using latest Pyramid to build a web app. Somehow we have started using Chameleon as the template engine. I have used Mako before and it was extremely simple to create a base template. Is this possible with chameleon as well?
I have tried to look through the docs but I can not seem to find an easy solution.
With Chameleon >= 2.7.0 you can use the "load" TALES expression. Example:
main.pt:
<html>
<head>
<div metal:define-slot="head"></div>
</head>
<body>
<ul id="menu">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<div metal:define-slot="content"></div>
</body>
</html>
my_view.pt:
<html metal:use-macro="load: main.pt">
<div metal:fill-slot="content">
<p>Bonjour tout le monde.</p>
</div>
</html>
Another option, which was used prior Chameleon got an ability to load templates from the filesystem, is to pass the "base" template as a parameter.
To simplify things, I often wrap such stuff into a "theme" object:
class Theme(object):
def __init__(self, context, request):
self.context = context
self.request = request
layout_fn = 'templates/layout.pt'
#property
def layout(self):
macro_template = get_template(self.layout_fn)
return macro_template
#property
def logged_in_user_id(self):
"""
Returns the ID of the current user
"""
return authenticated_userid(self.request)
which can then be used like this:
def someview(context, request):
theme = Theme(context, request)
...
return { "theme": theme }
Which then can be used in the template:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
metal:use-macro="theme.layout.macros['master']">
<body>
<metal:header fill-slot="header">
...
</metal:header>
<metal:main fill-slot="main">
...
</metal:main>
</body>
</html>
Make a template here:
<proj>/<proj>/templates/base.pt
with contents:
<html>
<body>
<div metal:define-slot="content"></div>
</body>
</html>
Use the template here:
<proj>/<proj>/templates/about_us.pt
by inserting the contents:
<div metal:use-macro="load: base.pt">
<div metal:fill-slot="content">
<p>Hello World.</p>
</div>
</div>