How can I display the values in HTML in Google App engine using Python?
I have retrieved the values and have stored them in a variable.
I tried the following but it gave me an error.I would like to display the records retrieved using a for loop but have no idea please help.
Code:
import cgi
import webapp2
from google.appengine.ext import db
form="""<!DOCTYPE html>
<html>
<head>
<title>ascii</title>
</head>
<body>
<h1>/ascii</h1>
<form method="post">
<label>
<div>Title</div>
<input type="text" name="text" value="%(text)s">
</label>
<br>
<label>
Art
<br><textarea cols="50" rows="12" name="art" value="%(art)s"></textarea>
</label><br>
<input type="submit">
<div style="color:blue">%(error)s</div>
</form>
<hr>
<hr>
***{%for art in arts %}
<div>
<div>{% art.title %}</div>
<pre>{%art.art%}</pre>
</div>***
</body>
</html>"""
class Art(db.Model):
title = db.StringProperty(required=True)
art=db.TextProperty(required=True)
created=db.DateTimeProperty(auto_now_add=True)
class MainHandler(webapp2.RequestHandler):
def write_form(self,error="",text="",art="",arts=""):
***arts=db.GqlQuery("select * from Art order by created DESC")***
self.response.out.write(form %{"error":error,
"text":text,
"art":art)}
def escape_html(self,s):
return cgi.escape(s,quote=True)
def get(self):
self.write_form()
def post(self):
text1=self.escape_html(self.request.get("text"))
art1=self.escape_html(self.request.get("art"))
if text1 and art1:
a=Art(title=text1,art=art1)
a.put()
self.redirect("/")
else:
self.write_form("Both fields required",text1,art1)
app = webapp2.WSGIApplication([('/', MainHandler)],
debug=True)
This method is not scaling very well and it's not the right approach. Check out how the templates are being used in the Getting Started tutorial for Python on Google App Engine.
The general idea is that you are writing your HTML in a template and then by passing some parameters to it, you will be able to user for-loops, if-statements and many more.
Related
I want authenticated user to be able to post in this applications, How can I do that?
I tested that in sqlite admin in django and it's working fine, and now I want to allow user to post from the addvideo templates:
this is the models:
from django.db import models
from django.db.models.base import Model
from django.db.models.fields import CharField
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(null=False, blank=False)
title = CharField(max_length=25, blank=False)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
this is my addvideo templates:
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="card">
<div class="form-group m-3">
<label>Upload Your Video</label><br><br>
<input required
name="video"
type="file"
accept="video/*"
class="form-control-file">
</div>
<div class="form-group m-3">
<label for="title">Your Topic</label>
<input type="text" class="form-control" name="title" id="title">
</div>
<button type="submit" class="btn btn-primary">Add Post</button>
</div>
</form>
</div>
</div>
</div>
And this is my views.py file:
from django.shortcuts import render, redirect
from django.contrib.auth.models import User, auth
from django.contrib import messages
from .models import Post
def addvideo(request):
posting = Post.objects.all()
if request.method == 'POST':
file = request.FILES.get('video')
posting = Post.objects.create(
file=file
)
return redirect('home')
return render(request, 'addvideo.html', {'posting': posting})
def dashboard(request):
posting = Post.objects.select_related('user')
return render(request, 'dashboard.html', {'posting': posting})
def home(request):
posting = Post.objects.select_related('user')
return render(request, 'home.html', {'posting': posting})
def viewVideo(request, pk):
posting = Post.objects.get(id=pk)
return render(request, 'video.html', {'posting': posting })
For me, the easiest way to solve this problem is by using CreateView.
views.py file:
from django.views.generic import CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Post # Will import Your `Post` model
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'file']
success_url = '/'
template_name = 'addvideo.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super(PostCreateView, self).form_valid(form)
model is the name of your model (In your case Post).
fields are the list of fields you want to display in template.
template_name is the path to your template.
success_url is the path where the user will be redirected when the Post is created successfully.
form_valid will save the current logged-in user as the owner of the post.
addvideo.html file:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit">
</form>
For using custom styles on your template, you can use django-widget-tweaks package, Here is a step-by-step tutorial on how to use this package link.
I am using CrashRpt C++ to upload crash reports from a piece of software I wrote. Crashrpt uploads the data from the crash report to a URL that is set when the program load, in the same way a browser would using a web form.
The CrashRpt send data like this HTML
<html>
<form action="THE_WEBSITE" method="POST" enctype="multipart/form-data">
Application name:<input type="text" name="appname">
Application version:<input type="text" name="appversion">
Email from:<input type="text" name="emailfrom">
Email subject:<input type="text" name="emailsubject">
Crash GUID:<input type="text" name="crashguid">
MD5:<input type="text" name="md5">
Attach ZIP file:<input type="file" name="crashrpt">
<input type="submit" name="Submit">
</form>
</html>
The only web service we have is the Google App Engine. Is there any way we can actually upload a file using a form to a static address and not the blobstore that requires a dynamic one.
I assume NO.
Here's a trivial, self-contained example of how to upload (small -- less than 1 MB!) files to a static url with GAE (with this example, use text files only, since that's how I display them):
import webapp2
from google.appengine.api import users
from google.appengine.ext import ndb
class UserFile(ndb.Model):
filename = ndb.StringProperty()
filedata = ndb.BlobProperty()
class UploadFormHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
self.response.out.write('<form action="/upload_file" method="POST" enctype="multipart/form-data">')
self.response.out.write(
'''Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form></body></html>''')
class UploadHandler(webapp2.RequestHandler):
def post(self):
thefile = self.request.POST.get('file')
filename = thefile.filename
userfile = UserFile(
id=filename, filename=filename,
filedata=thefile.value)
userfile.put()
self.redirect('/view_file/%s' % filename)
class ViewHandler(webapp2.RequestHandler):
def get(self, fileid):
k = ndb.Key(UserFile, fileid)
userfile = k.get()
self.response.headers['Content-Type'] = 'text/plain'
self.response.write(userfile.filedata)
app = webapp2.WSGIApplication([('/', UploadFormHandler),
('/upload_file', UploadHandler),
('/view_file/([^/]+)?', ViewHandler),
], debug=True)
I understand that uploading blob in Google App Engine is something like this:
<%
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
%>
<form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="submit" value="Submit">
</form>
Is it possible to save other input field? Let say we have other input in a form.
<input type="text" name="str" />
The answer is yes, it is possible. I'm successfully doing what you're asking about - uploading files and text on the same request in GAE. You just handle the request and its parameters in your request handler.
I'm new at GAE and all that python stuff, so question might be stupid at last.)
I have model:
from google.appengine.ext import db
class Task(db.Model):
name = db.StringProperty()
summary = db.StringProperty(multiline=True)
and I want to auto generate form, so:
import webapp2
import jinja2
import os
from wtforms.ext.appengine.db import model_form
from Tasks.model import Task
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__) + '/../templates/admin'))
class AddTaskPage(webapp2.RequestHandler):
def get(self):
AddForm = model_form(Task)
template_values = {
'form_self_link': self.request.path,
'form_content': AddForm
}
template = jinja_environment.get_template('add_task.html')
self.response.out.write(template.render(template_values))
add_task.html template:
<form method="POST" action="{{form_self_link}}">
{{form_content}}
<input type="submit" value="Add">
</form>
And the most confusing is output –
<form method="POST" action="/admin/tasks/add">
<class 'wtforms.ext.appengine.db.TaskForm'>
<input type="submit" value="Добавить">
</form>
There is NO form's elements, there is just very strange <class 'wtforms.ext.appengine.db.TaskForm'> stuff.
I use GAE 1.6.1, python 2.7.2, jinja 2.6 (bundled with GAE), WTForms 0.6.3 (latest)
Could you please help?
UPDATE:
I've used instruction bundled with class and it is not working:
from google.appengine.ext import db
from tipfy.ext.model.form import model_form
# Define an example model and add a record.
class Contact(db.Model):
name = db.StringProperty(required=True)
city = db.StringProperty()
age = db.IntegerProperty(required=True)
is_admin = db.BooleanProperty(default=False)
new_entity = Contact(key_name='test', name='Test Name', age=17)
new_entity.put()
# Generate a form based on the model.
ContactForm = model_form(Contact)
# Get a form populated with entity data.
entity = Contact.get_by_key_name('test')
form = ContactForm(obj=entity)
The only strange moment is "from tipfy.ext.model.form import model_form" string, but I think it is just an error in docs.
UPDATE 2
Well I managed to get it work and may be I missed something, seems like there is no feature "auto print form" in WTForm. So it works now like that:
class AddTaskPage(webapp2.RequestHandler):
def get(self):
AddForm = model_form(Task)()
template_values = {
'form_self_link': self.request.path,
'form_name_field': AddForm.name
}
template = jinja_environment.get_template('add_task.html')
self.response.out.write(template.render(template_values))
And prints out
<form method="POST" action="/admin/tasks/add">
<input id="name" name="name" type="text" value="">
<input type="submit" value="Добавить">
</form>
Well... seems like the only option is to do something like in future (taken from docs)
<form method="POST" action="/...">
<div>{{ form.username.label }}: {{ form.username(class="css_class") }}</div>
<div>{{ form.password.label }}: {{ form.password() }}</div>
<!-- and so on .... -->
</form>
Is it really no any auto-generate and auto-print form libraries for GAE with Python 2.7?(
LAST UPDATE
Well... I found one option to get it work and render all form elements:
class AddTaskPage(webapp2.RequestHandler):
def get(self):
addForm = model_form(Task)()
template_values = {
'form_self_link': self.request.path,
'form': addForm
}
template = jinja_environment.get_template('add_task.html')
self.response.out.write(template.render(template_values))
def post(self):
addForm = model_form(Task)(self.request.POST)
template_values = {
'form_self_link': self.request.path,
'form': addForm
}
template = jinja_environment.get_template('add_task.html')
self.response.out.write(template.render(template_values))
In template:
{% for field in form %}
<tr>
<th>{{ field.label }}</th>
<td>{{ field }}</td>
</tr>
{% endfor %}
Looks not so bad .)
I think you have to pass AddForm.content as a template value (instead of AddForm)
template_values = {
'form_self_link': self.request.path,
'form_content': AddForm**.content**
}
UPDATE
found this in the docs
(http://wtforms.simplecodes.com/docs/0.6.1/ext.html#wtforms.ext.appengine.db.model_form)
wtforms.ext.appengine.db.model_form(model)
Creates and returns a dynamic wtforms.Form class for a given db.Model class. The form class can be used as it is or serve as a base for extended form classes...
So what you are passing into the template is the class, not an instance of it.
AddForm = model_form(Task)()
Given the html form ...
<form id="mainform" action="/upload" enctype="multipart/form-data" method="post">
<div>
<input type="file" name="img"/>
</div>
<div>
<input type="submit" value="Send">
</div>
</form>
... and the handler ...
class Picture(db.Model):
image = db.BlobProperty()
class Submission(webapp.RequestHandler):
def post(self):
picture = Picture()
image = self.request.get("img")
picture.image = db.Blob(image)
picture.put()
self.redirect('/')
... is there any way within the handler to get the filename the user entered for the upload? In PHP, I can refer to $_FILES['img']['name'], but I do not see what syntax, if any, would work with request.get. In another question, another author uses a javascript routine in his html page to extract the filename the user chooses every time an OnChange event occurs, and then pass it separately in a hidden field. Is that necessary? PHP seems to get the filename for free.
I uncovered a solution in the documentation for the cgi module:
picture.local_filename = self.request.POST[u'img'].filename
The request's POST object is a collection of FieldStorage, and FieldStorage objects have a filename attribute.