google app engine with django upload file error - python

i am using django with google app engine . i am trying to upload images.
i made a form
<form enctype="multipart/form-data" action="addImage" method="post">
<p>Title of the Image:
<input type="text" name="title" /></p>
<p>Please select image to upload:
<input type="file" name="img" required="True"/></p>
<p><input type="submit" value="Upload" /></p>
</form>
mapping it to this view
def addImage(request):
image = Image()
image.title = request.POST.get("title")
img = images.resize(request.POST.get('img'),50,50)
image.blob = db.Blob(img)
image.put()
return HttpResponse('<html><head><meta HTTP-EQUIV="REFRESH" content="2; url=/"></head><body>One item added successfuly </body></html>')
its giving me this error in the debugging session
Exception Type: NotImageError
Exception Value:Empty image data.
WHY?????

I haven't used Google App Engine, but this is how I would do it on a pure Django 1.3 installation:
forms.py:
from django import forms
from django.forms import fields
class UploadImageForm(forms.Form):
image_file = fields.ImageField()
views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from NAME_OF_YOUR_APP.forms import UploadImageForm
def addImage(request):
if request.method == 'POST':
upload_image_form = UploadImageForm(data=request.POST, files=request.FILES)
if upload_image_form.is_valid():
image_file = request.cleaned_data['image_file']
# do something with the image...
return ...
else:
upload_image_form = UploadImageForm()
context = {'form':upload_image_form}
return render_to_response('path/to/upload_template.html', context, context_instance=RequestContext(request))
upload_template.html:
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>{{ form.image_file.label_tag }}</td>
<td>{{ form.image_file }}</td>
<td>{% if form.image_file.errors %}{% for error in form.image_file.errors %}{{ error }}{% endfor %}{% endif %}</td>
</tr>
</table>
<input type="submit" value="Submit"/>
</form>
Your template code looks good (it's missing {% csrf_token %}, which I'm not sure if GAE needs or not). Your view code should check to see if the request is a POST request or not.
In my example, I created a form called UploadImageForm, which accepts a single image_file to be uploaded. Logic works like so:
User visits example.com/upload_image
addImage() runs. Since this is a GET and not a POST request, it makes an empty UploadImageForm(), and renders it inside upload_template.html.
User is displayed the form.
User fills out the form and Submits an image.
Server receives POST request, and addImage() is called again.
We bind the uploaded file data to UploadImageForm.
If there are no errors (e.g. upload_image_form.is_valid() is True), we capture the image_file out of cleaned_data, and we can then do something with it.
If there are errors (upload_image_form.is_valid() is False), the template is re-displayed with error messages.

really simple ,
edit this line:
img = images.resize(request.POST.get('img'),50,50)
with this one:
img = request.FILES['img'].read()
make sure that you are using django 1.2

Try this.. it work for me... :)
def addImage(request):
image = Image()
image.title = request.POST.get("title")
image.blob = db.Blob(str(request.FILES['img']['content']))
image.put()
return HttpResponse('<html><head><meta HTTP-EQUIV="REFRESH" content="2; url=/"></head><body>One item added successfuly </body></html>')

Related

Django - Post to specific URL using form

I want to post to a specific URL. The url has the scope of deleting a database row. The URL is composed by the address + the pk of the file selected in the form catched from a model.
select_file_deletion.html
{% extends "index.html" %}
{% block content %}
<!--Here the number 2 in "/App/delete/2/" needs to be replaced with the pk of the file. The logic is working. -->
<form action="/App/delete/{{ myfile.pk }}/" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<h5>Please select one file at a time from the list below to delete it from the server.</h5>
{% for myfile in filename %}
<input type="checkbox" name="file_name" value="{{ myfile }}">
<label>
{{ myfile }}
<input type="hidden" value="{{ myfile.pk }}" name="pk">
</label>
<br>
{% endfor %}
<br>
<button type="submit" class="btn btn-primary">Delete</button>
</form>
{% endblock %}
Project urls.py
url(r'^delete/(?P<pk>\d+)/$', FileDeleteView.as_view(), name='APIdelete')
views.py
class SelectFileDelView(TemplateView):
"""
This view is used to select a file from the list of files in the server.
After the selection, it will send the file to the server.
The server will then delete the file.
"""
template_name = 'select_file_deletion.html'
parser_classes = FormParser
queryset = FileModel.objects.all()
def get_context_data(self, **kwargs):
"""
This function is used to render the list of files in the MEDIA_ROOT in the html template.
"""
context = super().get_context_data(**kwargs)
media_path = settings.MEDIA_ROOT
myfiles = [f for f in listdir(media_path) if isfile(join(media_path, f))]
context['filename'] = myfiles
return context
class FileDeleteView(DeleteView):
"""
This class contains the method to delete a file interacting directly with the API.
DELETE requests are accepted.
"""
# TODO: Fix, still not working
model = FileModel
fields = ['file']
template_name = 'delete_success.html'
success_url = '/delete_success/'
App/urls.py
# Url to select a file to be deleted and confirm the upload
url('filedelete/', SelectFileDelView.as_view(), name='file_delete'),
url('delete_success/', FileDeleteView.as_view(), name='delete_success')
ERROR: the request URL row is not catching the address including the pk, not replacing the variable with the pk of the selected file.
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/App/delete//
Using the URLconf defined in DjangoRestDeepLearning.urls, Django tried these URL patterns, in this order:
^App/ ^predict/$ [name='APIpredict']
^App/ ^upload/$ [name='APIupload']
^App/ ^delete/(?P<pk>\d+)/$ [name='APIdelete']
filedelete/ [name='file_delete']
delete_success/ [name='delete_success']
The current path, App/delete//, didn't match any of these.
Question I checked before opening this one without solving the issue:
1) Delete object with form in django
2) Django How to pass object id via form action?
Im assuming you have the myfile.pk in your template.
The url in your form action isnt working as the pk is missing. Replace the action of the form with this:
<form action="{% url 'APIdelete' pk=myfile.pk %}" method="post" enctype="multipart/form-data">

How to transfer Checkbox parameters in Django Materialized view?

The setup contains Django with Materialize view library.
Two questions:
1) How to transfer parameters from html to .py -file when using Materialize checkbox?
2) If this works, then how to keep them in a session so that when next time visiting on page, the checkboxes are not empty?
I have googled a lot and made many trials with no success.
Library: href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
homepage.html:
<form action="#">
{% for sites in wsites %}
<label >
<input type="checkbox" name="option{{sites.id}}" id="option{{sites.id}}" value={{sites.id}}/>
<span>{{sites.name}} </span>
</label>
<br>
{% endfor %}
</form>
views.py
def homepage(request):
if request.method == 'POST':
print(request.POST)
return render(request = request,
template_name='main/home.html',
context = {"wsites":Sites.objects.all })
Session parameters is an empty list, ie. print(request.POST) = []. I would appreciate to get some help how to resolve this.

Python Flask Sqlite3 Web App Delete from database table row

I have a very simple application that creates, removes, and updates records in a sqlite3 database using Python and Flask. I am currently working on the remove function and have hit a road block. Below is my code for my view that shows the records in the table:
<!doctype html>
<html>
<body>
<table border = 1>
<thead>
<td>Name</td>
<td>Address>/td<
<td>city</td>
<td>Pincode</td>
</thead>
{% for row in rows %}
<tr>
<td>{{row["name"]}}</td>
<td>{{row["addr"]}}</td>
<td> {{ row["city"]}}</td>
<td>{{row['pin']}}</td>
<td><form action = "/foo" method = "POST">
<button id ="w3-btn">delete</button>
</form> </td>
</tr>
{% endfor %}
</table>
Go back to home page
</body>
</html>
As can be seen from the code, I have a delete button for each record displayed. How can I make it such that if the user clicks on the delete button on any given row, that row will be deleted from the table? I would like to know how I can specify the selected row, and how I can send that information/data to 'foo' in my app.py, and how the function in app.py would take that data as an input argument.
If you have row["pin"]
then you can use hidden field in form with method="POST"
<form action="/foo" method="POST">
<input type="hidden" value="{{ row["pin"] }}"/>
<button id="w3-btn">delete</button>
</form>
or using method="GET" and ?id=some_id in url
<form action="/foo?id={{ row["pin"] }}" method="GET">
<button id="w3-btn">delete</button>
</form>
Or even as normal link (which you can style as button using CSS)
delete
In view you will have
# POST
#app.route('/foo', methods=['POST'])
def foo():
pin = requests.form.get('id')
print(pin)
# GET or normal link
#app.route('/foo')
def foo():
pin = requests.args.get('id')
print(pin)
Read doc: http://flask.pocoo.org/docs/0.11/
If you use url without ?id= but "/foo/some_id"
action="/foo/{{ row["pin"] }}"
delete
or using url_for()
action="{{ url_for('foo', pin=row["pin"]) }}"
TEST
then you will need
#app.route('/foo/<pin>')
def foo(pin):
print(pin)
Create a delete view that takes an id to delete.
#app.route('/<int:id>/delete', methods=['POST'])
def delete(id):
r = Record.query.get_or_404(id)
db.session.delete(r)
db.session.commit()
return redirect(url_for('index'))
The delete form's action is the generated url to the delete view.
<form method=post action="{{ url_for('delete', id=r.id) }}">
This assumes that each row has an id attribute. For example:
from flask import Flask, redirect, url_for, render_template_string
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
db.create_all()
db.session.add_all((
Item(name='abc'),
Item(name='def'),
Item(name='ghi'),
))
db.session.commit()
#app.route('/')
def index():
items = Item.query.all()
return render_template_string('''<ul>{% for item in items %}
<li>{{ item.name }} -
<form method=post action="{{ url_for('delete', id=item.id) }}">
<button type=submit>delete</button>
</form></li>
{% endfor %}</ul>''', items=items)
#app.route('/<int:id>/delete')
def delete(id):
item = Item.query.get_or_404(id)
db.session.delete(id)
db.session.commit()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)

Using Django FormPreview the right way

My Goal
I have a django project with a form, and I want to display a preview page before the user submits.
The problem
I can display a preview page using a Django FormPreview, but not all form data is displayed properly. Specifically, if I have a field with choices, the string values of these choices aren't displayed. I'm also having problems applying template filters to date fields. The end result is that some data on the preview page is visible but other data is blank:
However, if I display the same data for posts that have actually been submitted, then everything displays properly:
My Code
models.py:
class Game(models.Model):
# Game Choices
FOOTBALL = 0
BASKETBALL = 1
TENNIS = 2
OTHER = 3
GAME_CHOICES = (
(FOOTBALL, 'Football'),
(BASKETBALL, 'Basketball'),
(TENNIS, 'Tennis'),
(OTHER, 'Other')
)
game_id = models.AutoField(primary_key=True)
location = models.CharField(max_length=200, verbose_name="Location")
game = models.IntegerField(choices=GAME_CHOICES, default=FOOTBALL)
game_date = models.DateField(verbose_name='Game Date')
forms.py
class GameForm(ModelForm):
class Meta:
model = Game
fields = (
'location',
'game',
'game_date'
)
I'm pretty sure that the problem is in my views.py: I'm not sure that I'm processing the POST request the right way to feed all data to the preview page.
views.py
def form_upload(request):
if request.method == 'GET':
form = GameForm()
else:
# A POST request: Handle Form Upload
form = GameForm(request.POST) # Bind data from request.POST into a GameForm
# If data is valid, proceeds to create a new game and redirect the user
if form.is_valid():
game = form.save()
return render(request, 'games/success.html', {})
return render(request, 'games/form_upload.html', {
'form': form,
})
preview.py
class GameFormPreview(FormPreview):
form_template = 'games/form_upload.html'
preview_template = 'games/preview.html'
def done(self, request, cleaned_data):
# Do something with the cleaned_data, then redirect
# to a "success" page.
return HttpResponseRedirect('/games/success')
form_upload.html
...
<form method="post">
{% csrf_token %}
<ul><li>{{ form.as_p }}</li></ul>
<button type="submit">Preview your post</button>
</form>
...
preview.html
{% load humanize %}
...
<h1>Preview your submission</h1>
<div>
<p>Location: {{ form.data.location }}</p>
<p>Game Date: {{ form.data.game_date|date:"l, F d, Y" }}</p>
<p>Game Type: {{ form.data.get_game_display }}</p>
</div>
<div>
<form action="{% url 'form_upload' %}" method="post">
{% csrf_token %}
{% for field in form %}
{{ field.as_hidden }}
{% endfor %}
<input type="hidden" name="{{ stage_field }}" value="2" />
<input type="hidden" name="{{ hash_field }}" value="{{ hash_value }}" />
<!-- Submit button -->
<button type="submit">Submit your post</button>
<!-- Go back button -->
<button type="submit">
<a href="{% url 'form_upload' %}"
onClick="history.go(-1);return false;" >
Go back and edit your post
</a>
</button>
</div>
</form>
</div>
...
Two issues
Essentially, I'm having these two issues:
String values for choices are not displayed. If I use the get_FOO_display() method in my preview.html template, it returns blank. However, if I use this in a page after the post has been submitted, it displays properly.
The humanize date filter doesn't work. If I apply a humanize filter ({{ form.data.game_date|date:"l, F d, Y" }}) in preview.html, it also displays blank. Again, this works for submitted posts.
My question essentially is: what's the right way to use the FormPreview here?
form.data does not have get_FOO_display attributes. When you access {{ form.data.get_game_display }} in the template, it fails silently and doesn't display anything.
The get_FOO_display are methods of the instance, so try this instead.
{{ form.instance.get_game_display }}
Wherever possible you should access data from form.cleaned_data (which is validated and 'cleaned') instead of form.data, which is the raw data submitted to the form.
The filters don't work with form.data.game_date because it's a raw string. They should work with form.cleaned_data.game_date, which has been converted to a python date object.
Finally, you haven't implemented anything in your done method, you've just copied the comment from the docs. You could create a new game using cleaned_data as follows:
def done(self, request, cleaned_data):
game = Game.objects.create(**cleaned_data)
return HttpResponseRedirect('/games/success')

WTforms form not submitting but outputs no validation errors

I'm trying to get file uploads with flask-uploads working and running in to some snags. I'll show you my flask view function, the html and hopefully someone can point out what I'm missing.
Basically what happens is that I submit the form and it fails the if request.method == 'POST' and form.validate(): check in the view function. It jumps down to display the template. wtforms isn't kicking me any errors on the form so I'm wondering why its failing that if statement.
What am I over looking?
Setting up flask-uploads:
# Flask-Uploads
photos = UploadSet('photos', IMAGES)
configure_uploads(app, (photos))
View:
def backend_uploadphoto():
from Application import photos
from Application.forms.backend import AddPhotoForm
clients = Client.query.all()
events = Event.query.order_by('date').all()
form = AddPhotoForm(request.form, csrf_enabled=True)
if request.method == 'POST' and form.validate():
from uuid import uuid4
uuid = uuid4()
filename = '{0}.jpg'.format(uuid)
photo = Photo(uid=uuid, client=request.form['client'], event=request.form['event'])
photofile = photos.save(request.files.get('photo'), photo.filename)
return redirect(url_for('backend'))
return render_template('backend/addphoto.html', form=form, clients=clients, events=events)
Form:
class AddPhotoForm(Form):
photo = FileField('Photo')
client = IntegerField('Client:')
event = IntegerField('Event:')
HTML:
<form action="{{url_for('backend_uploadphoto')}}" method="post">
<p>
{{form.client.label}}
<select name="client">
{% for client in clients %}
<option value="{{client.id}}">{{client.fullname}}</option>
{% endfor %}
</select>
{{form.client.errors}}
</p>
<p>
{{form.event.label}}
<select name="event">
{% for event in events %}
<option value="{{event.id}}">{{event.name}}</option>
{% endfor %}
</select>
{{form.event.errors}}
</p>
<p><label for="photo">Photo:</label>{{form.photo}} <input type="submit" value="Upload"> {{form.photo.errors}}</p>
</form>
You have csrf_enabled=True but your form doesn't have any CSRF protection since you aren't inheriting from SecureForm. If you want to enable CSRF, read the documentation and update your form definition.
If this was unintended, you can remove csrf_enabled=True and your logic will work as expected.
To enable CSRF protection, there are a few steps:
Inherit from SecureForm
Create the generate_csrf_token and validate_csrf_token methods in your form. These methods will generate a unique key and raise errors when it doesn't validate.
Add {{ form.csrf_token }} to your template.

Categories

Resources