I am trying to render data into a template file using the following Code. The error I encounter is something like :
This page contains the following errors:
error on line 13 at column 16: AttValue: " or ' expected
Below is a rendering of the page up to the first error.
Name,Author,Status
Code
def editbook(request):
if request.method == 'GET':
name = request.GET.get('name',False)
Details = bookInfo.objects.all().filter(Name=name)
id = Details.values_list('id',flat=True)
Name = Details.values_list('Name',flat=True)
Author = Details.values_list('Author',flat=True)
Status = Details.values_list('Status',flat=True)
return render(request, 'app/add.html', {'Name' : Name, 'Author' : Author, 'Status' : Status}, content_type="application/xhtml+xml")
Template Code
<html>
<head>
<title>Add</title>
</head>
<body>
<form action="add/" method="post">
{% csrf_token %}
<p style="font-family:Courier New;color:teal">Name <input type="text" placeholder="Name of the book" name="name"></input></p>
<p style="font-family:Courier New;color:teal">Author <input type="text" placeholder="Author of the book" name="author"></input></p>
<p style="font-family:Courier New; color:teal"> Status
<select name="status">
<option value=1>Read</option>
<option value=1>Unread</option>
</select>
</p>
<input type="submit" id="booksubmit" value="Add/Edit Book"></input>
</form>
</body>
</html>
I searched through Google and I found that this somewhat like XML parsing error (Please correct me if I am wrong). Now I am stuck at this position. Please help.
EDIT Here the form for adding the book has a different method for saving the field data into database.
Your HTML is malformed for whatever type is is, html and html5.
And to be picky, your python code should be refactored as well.
Normally we define variables with lowercase letter instead of a capital so
the variables Details, Name, Author, Status should be details, name, author, status.
Further more, is your class name bookInfo spelled like that?
Classes in python should start with a capital letter so bookInfo should be BookInfo.
The proper HTML5 is this:
<html>
<head>
<title>Add</title>
</head>
<body>
<form action="add/" method="post">
{% csrf_token %}
<p style="font-family:Courier New;color:teal;">Name <input type="text" placeholder="Name of the book" name="name" /></p>
<p style="font-family:Courier New;color:teal;">Author <input type="text" placeholder="Author of the book" name="author" /></p>
<p style="font-family:Courier New; color:teal;"> Status
<select name="status">
<option value=1>Read</option>
<option value=1>Unread</option>
</select>
</p>
<input type="submit" id="booksubmit" value="Add/Edit Book" />
</form>
</body>
</html>
If you're not using HTML5 and that depends on the Doctype you've defined.
You can't use placeholders in your input fields.
The inputs need to get closed with a /> and not a </input>.
The inline styles you've provided in your html is incomplete:
style="font-family:Courier New; color:teal"
should be
style="font-family:Courier New; color:teal;"
The return you're using doesn't need a content_type you can drop that.
You're not using your template variables anywhere so that's not it but if you would like to start using them the syntax for the template language is {{ variable_name }} and in your case that would be (until you refactor)
{{ Name }}, {{ Status }} for example.
Also you're seeing this error because of the content_type since you're actively telling the browser to parse the document as xhtml+xml and that's XHTML with rules, which you're effectively breaking.
For adding the value from your Django app to your input fields do this, (without a Django Form)
<input type="text" value="{{ Name }}" />
But I would recommend using a Django Form instead.
I think you're getting this error because you're template is not 'well formed'. My guess is that there's an error in the xml that's being output.
You've declared the content type of your http response to be application/xhtml+xml. xhtml requires you to put quotes around all your attributes. You're probably missing/adding a quotation mark somewhere. I can't see from your template where that is.
Either check what your template variables ({{ Name }}, {{ Author }} and {{ Status }}) are outputting to see if they're adding in a stray quotation mark, or try changing the content type (maybe just drop the content_type parameter you're passing to the render function).
Related
I have two input buttons. One is for uploading a file, and the other one is a submit button that adds the uploaded file to the database.
My problem is, after I submit the file, the first button that's used for uploading goes back to "No file chosen" next to the button. However, I want the uploaded file name to "stick" to the UI/html page as the file chosen.
Here is my File class:
class Files(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True, nullable=False)
data = db.Column(db.LargeBinary)
Here is my HTML code:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload" value ="{{row.name}}"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I've tried making the value attribute equal to the file name getting passed in ex. value ="{{row.name}}" for the file type <input> above, but that doesn't keep the file chosen name on the page after submission either. I can't find any videos or posts that deal with this problem, so I would really appreciate any guidance. TIA!
I think setting a default value for an input field of type file is forbidden for security reasons.
However, if you want to keep the name of the selected file, you can aim for a transfer with AJAX. Here you can suppress the standard behavior of the form. The page is not reloaded and the form is not reset.
The example below shows you how it works.
Flask (app.py)
from flask import Flask
from flask import (
render_template,
request,
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload-file', methods=['POST'])
def upload_file():
if 'csvfile' in request.files:
file = request.files['csvfile']
if file.filename != '':
# handle file here!
return '', 200
return '', 400
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form name="my-form" method="post">
<input type="file" name="csvfile" />
<input type="submit" />
</form>
<script type="text/javascript">
((uri) => {
const elem = document.querySelector('form[name="my-form"]');
elem.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'post',
body: formData
}).then(resp => {
if (resp.status === 200) {
console.log('Submit successful.');
}
});
})
})({{ url_for('.upload_file') | tojson }});
</script>
</body>
</html>
I don't know if it is possible to default the value the file-input field shows but what you could do is just have a row above the input field showing the currently uploaded/chosen file (if there is any). So something like this:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
{% if row.name %}
<p>Currently chosen file: {{row.name}}</p>
<p>You can select a new file below</p>
{% endif %}
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I am creating a website and already finished the frontend. Now I want to handle a form submit post request using python. I am trying to do this using django, but I can't figure out how I would
attach CSS classes, onchange eventhandlers and IDs to the django forms
insert divs and other html elements in between the django input elements within a single form
This is my current frontend:
<form method="post" autocomplete="off">
<p class="sub-header">Or just leave Us a Message:</p>
<div>
<div id="contact-layout">
<div class="input-container">
<input type="text" name="name" placeholder="Name">
<div class="input-bar"></div>
</div>
<div class="input-container">
<input type="text" name="email" placeholder="Email">
<div class="input-bar"></div>
</div>
<div class="input-container">
<input type="text" name="subject" placeholder="Subject">
<div class="input-bar"></div>
</div>
</div>
<div class="input-container">
<textarea name="message" placeholder="Type your message here..." id="message-input"></textarea>
<div class="input-bar"></div>
</div>
</div>
<div>
<p class="sub-header" id="user-image-header">Attach some images:</p>
<div id="file-upload">
<span class="form-button">Choose Files</span>
<input id="upload" type="file" onchange="LoadImage(this)" name="image" accept="image/*" multiple>
</div>
</div>
<div class="delimiter"></div>
<input class="form-button" type="submit" id="contact-submit" value="Submit">
<p id="submit-thanks">Thanks for submitting!</p>
as you can see I have a few "normal" html text inputs, a text area and an input for multiple image files.
In django I linked my static css files and setup my html frontend as a django template.
My django form looks like this so far:
class ContactForm(forms.Form):
name = forms.CharField()
email = forms.CharField()
phone = forms.CharField(required=False)
subject = forms.CharField(required=False)
message = forms.CharField(widget=forms.Textarea)
When I insert it into my frontend, It obviously doesn't look that good, as I have no Idea how I would represent my rather complex form design using django.
Could you point out how you would do this or maybe link a few good guides on how to approach something like this?
Also if possible provide some code examples :)
FYI I am familiar with python but I have never used django before, so maybe I am missing something obvious as for me it seem kind of overwhelming in it's complexity as a framework.
A good starting point is to familiarize yourself with what a default Django form generates. Here, for example, I was finding out for myself about the CheckboxSelectMultiple widget:
>>> class ZForm( forms.Form):
... foo = forms.MultipleChoiceField( choices=(('A','AA'),('B','BB'), ('C','CC')), widget=forms.CheckboxSelectMultiple )
...
>>> z = ZForm()
>>> z.as_p()
'<p><label>Foo:</label> <ul id="id_foo">\n <li><label for="id_foo_0"><input type="checkbox" name="foo" value="A" id="id_foo_0" />\n AA</label>\n\n</li>\n <li><label for="id_foo_1"><input type="checkbox" name="foo" value="B" id="id_foo_1" />\n BB</label>\n\n</li>\n <li><label for="id_foo_2"><input type="checkbox" name="foo" value="C" id="id_foo_2" />\n CC</label>\n\n</li>\n</ul></p>'
>>>
If you want to style it with css, the css ids generated by Django make it fairly. straightforward to describe any elements with css locators.If you don't want the default Django layouts, you can generate the form field-by-field in your template, or you can learn about django-crispy-forms (especially, layout helpers) which I wholeheartedly recommend.
As for where to inject css into Django, there are various ways, but a common one is through a block called something like css in your base template. The view template will look something like
{% extends "base.html" %}
{% block content %}
<!-- code to render your form -->
...
{ %endblock content %}
{% block css %}
/* base.html provides the surrounding style tags */
/* block.super inherits the css common to all pages using base.html */
{{block.super}}
/* additional styling for the form rendered in block content */
#id_foo label {
/* styling for labels on the foo field only */
whatever;
}
{% endblock css %}
In passing my own base.html also always loads Jquery (unsurprisingly in a block called scripts so I can per-template-override or augment should I need to) and has a block onready_js that gets rendered in this context, which saves an awful lot of easily-mistyped boilerplate around what can be a trivial Jquery snippet
<script type="text/javascript"> $(document).ready( function() {
{% block onready_js %}{% endblock onready_js %}
});
</script>
and you just put any per-template Jquery you need to be executed when the view is invoked into that block.
You can develop frontend and backend seperately in django. You can create a form on frontend and style it and handle it on your backend as
def my_route_handler(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
# do your processing
# return
There is no need to embed the django form in frontend.
I'm working on a simple UI to start and stop games by ID. The basic HTML I have written is as follows (game_id is populated by JS):
<div align="center" class="top">
<div align="left" class="game-id-input">
Game ID: <input type="text" name="game_id" id="game_id">
</div>
<div align="right" class="buttons">
<form action="{{ url_for('start_game', game_id=game_id) }}" method="get">
<input type="submit" name="start" value="Start game" class="btn btn-success"></input>
</form>
<form action="{{ url_for('end_game', game_id=game_id) }}" method="get">
<input type="submit" name="end" value="End game" class="btn btn-danger"></input>
</form>
</div>
</div>
which looks like
I also have Flask route functions defined for each of the forms:
#app.route("/start_game/<game_id>")
def start_game(game_id):
# ...
#app.route("/end_game/<game_id>")
def end_game(game_id):
# ...
In my forms, how can I make game_id correspond to the game_id from #game_id?
Currently when I submit start and end games, I get a File Not Found error because it's just appending the literal <game_id> to the route.
I'm new to web development. This should be trivial, but I don't know what to search for. Sorry in advance for such a simple question.
You are trying to generate a url based on user input, but user input isn't available when Jinja is rendering the template on the server side, it's only available on the client side. So if you wanted to post to URLs with the game id as a URL parameter, you would have to build that URL on the client side with JavaScript.
For what you're trying to do, that's not really necessary. You can get the submitted value of a named input with request.form['name']. Buttons are just like any other input, so you can name them to find out what action was taken.
#app.route('/manage_game', methods=['POST'])
def manage_game():
start = request.form['action'] == 'Start'
game_id = request.form['game_id']
if start:
start_game(game_id)
else:
stop_game(game_id)
return redirect(url_for('index'))
<form method="POST" action="{{ url_for('manage_game') }}">
<input type="text" name="game_id"/>
<input type="submit" name="action" value="Start"/>
<input type="submit" name="action" value="Stop"/>
</form>
Even that's more verbose than you need. Given that you'd know if a game was already in progress, just toggle the current status instead of picking an action. It would never make sense to start a game that's already started, only stop it.
I cannot comment, but I would like to correct davidism's code.
I believe that you need action within your form element with a value which corresponds to the function within the server python code for this to work. Minor, but an important correction. So it would be like this:
In your server.py:
#app.route('/manage_game', methods=['POST'])
def manage_game():
start = request.form['action'] == 'Start'
game_id = request.form['game_id']
if start:
start_game(game_id)
else:
stop_game(game_id)
return redirect(url_for('index'))
In your HTML:
<form method="POST" action=/manage_game>
<input type="text" name="game_id"/>
<input type="submit" name="action" value="Start"/>
<input type="submit" name="action" value="Stop"/>
</form>
I read through Flask-WTF extremely simplified wiki, and couldn't understand much about what I can do with it. I am under the impression that the <form> section of the html now can only look like
<form method="post">
{{ form.hidden_tag() }}
{{ form.name }}
<input type="submit">
</form>
But I really want to style my using materialized such as:
<div class="row">
<div class="input-field col s6">
<i class="material-icons prefix">account_circle</i>
<input value="FN" id="first_name" type="text" class="validate">
<label class="active" for="first_name">First Name</label>
</div>
<div class="input-field col s6">
<input value="LN" id="last_name" type="text" class="validate">
<label class="active" for="last_name">Last Name</label>
</div>
</div>
Where can I fit {{ form.first_name }} and {{ form.last_name }} into?
EDIT: Let me elaborate on my answer a bit more:
For example, I want something like Materialized datepicker (a good pop up calendar that lets user to choose the date), this should be in the <input class='datepicker' length="50">, but now that I am replacing the whole <input> line with {{ form.date }}... I lost that privilege to edit the class and what not.
WTForms fields can be called with attributes that will be set on the input they render. Pass the attributes you need for styling, JavaScript functionality, etc. to the fields, rather than just referencing the fields. The labels behave the same way, and can be accessed with field.label.
for, value, type, id, and name do not need to be passed, as they are handled automatically. There are some rules for handling special cases of attributes. If an attribute name is a Python keyword such as class, append an underscore: class_. Dashes are not valid Python names, so underscores between words are converted to dashes; data_toggle becomes data-toggle.
{{ form.first_name(class_='validate') }}
{{ form.first_name.label(class_='active') }}
{{ form.begins(class_='datepicker', length=50) }}
Note that neither of the linked methods need to be called directly, those docs just describe the behavior when calling the fields.
In WTForms 2.1 I use extra_classes, like the line below:
1. The first way
{{ f.render_form_field(form.first_name, extra_classes='ourClasses') }}
or maybe in your case just like this:
{{ form.first_name, extra_classes='ourClasses' }}
We can also use the render_kw attribute on our form field like the second way below:
2. The second way
style={'class': 'ourClasses', 'style': 'width:50%; other_css_style;'}
first_name = StringField('First name',
validators=[InputRequired(),Length(1, 64)],
render_kw=style)
But I would prefer to use the first way.
So, I did some benchmarks to see how many requests the app could handle. It turns out that when a database operation is involved, no more than 500-560 requests/sec can be handled before timing out subsequent requests, whereas without the database layer it easily comes to a whopping 1000-1100 requests/sec.
I still didn't manage to cut the db costs in most of the pages (and I'm working on it), but there's one where this overhead can be cut: the edit page.
I have the following view which is executed when you visit http://website.com/edit. What it does is get the id parameter in the url and find the post from the db (MongoDB) with it, which then pass the iterated output to the template:
def edit(id):
item = mongo.db.documents.find_one({'_id': id})
doc = item.iteritems()
return render_template('edit.html',
content=item[0],
title=item[3],
url=item[2],
id=post[1]
)
This code is executed when you click edit in the item page, which is made like this:
{% block body %}
{{ title }}
<p>{{ content }}</p>
<div>
<a href=delete>Delete</a>
<a href=edit>Edit</a>
</div>
<form method="post" action="/post">
<input type="hidden" name="id" value="{{ id }}" />
<input type="hidden" name="url" value="{{ url }}" />
<input type="hidden" name="title" value="{{ title }}" />
<input type="hidden" name="content" value="{{ content }}" />
<div>
<h5>Your Name :</h5>
<input type="text" name="name" id="add_comment_author" />
</div>
<div>
<h5>Your Thought :</h5>
<textarea name="content id="add_comment_content"></textarea>
</div>
<input type="submit" value="Send" />
</form>
{% endblock %}
As you can see there are already hidden inputs with the needed value, but they're used for the comments.
Is it possible to do something like this?:
def edit(id):
#item = mongo.db.documents.find_one({'_id': id})
#doc = item.iteritems()
doc = request.get.previous()
return render_template('edit.html',
content=doc[0],
title=doc[3],
url=doc[2],
id=doc[1]
)
Alternatively would it be possible to have two POST in one page (one for sending a comment, the other for sending the values to the edit page?
Or maybe use Flash? But I suspect that's highly suboptimal and prone to bugs.
Typical solution is to use a caching layer like Flask-Cache and a memcached server to cache recently accessed data.
Having an edit form in the page is good. You can have as many forms as you want. Btw the common approach is to have only some sort of "templated" forms hidden that you'll then fill using jQuery os similar JS libraries.
In your example you're also passing the content field as hidden. Why? One might modify your source and change the content. :)