Django Reportlab generates empty pdf - python

I'm using reportlab to create a pdf. I am using Reportlab Paragraphs. The problem is everytime i download it, it generates an empty txt.
I tested it without django and it works without a problem. If i'm using canvas it works but it doesn't suit what i need.
views.py
from django.http import HttpResponse
from django.shortcuts import render
from reportlab.lib.enums import TA_JUSTIFY
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.pagesizes import letter
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
doc = SimpleDocTemplate("example.pdf", pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
return response
return render(request, 'pdf_test.html')
pdf_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Download pdf</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
<button type="submit">Download</button>
</form>
</body>
</html>
What seems to be the problem?

You have to write the file to stream. Try this:
from io import BytesIO
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
buff = BytesIO()
doc = SimpleDocTemplate(buff, pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
response.write(buff.getvalue())
buff.close()
return response
return render(request, 'pdf_test.html')

The function was generating two files, one in Downloads as default but it was an empty txt and one in the project's directory. I've made the changes.
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
doc = SimpleDocTemplate(response, pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
return response
return render(request, 'pdf_test.html')

Related

How to convert webscraping into django api?

I'm trying to scrape some data on two websites. I successfully scraped it. I also want to develop an API using this scraped data using Django. But when I try to display the scraped data in JSON format in Django. It only shows an empty list. Below I attached my code snippets.
from django.shortcuts import render
from bs4 import BeautifulSoup
import requests
import re
import json
import time
data = []
def getURL(url):
url = url.replace(' ', '-').lower()
for char in url:
if char in "?.!:;|/[]&()":
url = url.replace(char, '-')
if char == "'" or char == ",":
url = url.replace(char, '')
decodeUrl = re.sub(r'-+', '-', url)
# check whether the URL is up or not
parsedUrl = "http://www.tutorialbar.com/" + decodeUrl + "/"
if requests.head(parsedUrl).status_code == 200:
return parsedUrl
urls = ['https://www.discudemy.com/all', 'https://www.discudemy.com/all/2']
for url in urls:
source = requests.get(url).text
soup = BeautifulSoup(source, 'html5lib')
# print(soup)
for content in soup.find_all('section', class_="card"):
# print(content)
try:
language = content.label.text
header = content.div.a.text
day = content.find('span', class_="category").text
i = content.find('div', class_="image")
img = i.find('amp-img')['src']
image = img.replace('240x135', '750x422')
description = content.find('div', class_="description").text.lstrip()
myURL = getURL(header)
udemyURL = requests.get(myURL).text
udemySoup = BeautifulSoup(udemyURL, 'html5lib')
udemylink = udemySoup.find_all('a', class_="btn_offer_block re_track_btn")[0]["href"]
entry = {
'language': language,
'header': header,
'day': day,
'image': image,
'description': description,
'courselink': udemylink,
}
data.append(entry)
print()
except Exception as e:
continue
print(json.dumps(data))
print()
print(data)
def index(req):
return render(req, 'index.html', {'courses': json.dumps(data)})
Below is my HTML file for displaying JSON data.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>UdemyCourses</title>
</head>
<body>
{{ courses }}
</body>
</html>
There is some delay in scraping data. I think it might be a problem. I don't know how to handle asynchronous programming in python. Is there any way to achieve it? I'm a beginner. Help me out. Thanks in advance

How to show images from s3?

I'm finishing an application by django that generates pdf certificates
it was working great before I pull it into heroke and set up S3 amazom to host static files.
I have an html with the certificate template, and by HTML2PDF I render it to pdf. But it's not showing the background by css, it works just in the tag
Weird that if we opent the image url in s3 amazom it's shown perfectly
here the template css part
<meta charset="utf-8" />
{% load static %}
<style type="text/css">
#page {
size: 1122.52px 1587.4px ;
/*size: A4 landscape;*/
margin: 0cm;
background-image: url({{bg_front}});
height: 1588;
}
</style>
My view:
class ViewPDF(View):
def get(self, request, *args, **kwargs):
data = {}
pdf = True
if kwargs['pk']:
try:
participant = Participant.objects.get(pk=kwargs['pk'])
print(participant.cpf)
if participant.name:
certificate = Certificate.objects.get(pk=participant.certificate.pk)
pathBack = str(certificate.template.template_back.url)
pathFront = str(certificate.template.template_front.url)
print(pathFront)
#
# CONFIGURA OS BACKGROUNDS E TEXTO
#
data['bg_front'] = pathFront
data['bg_back'] = pathBack
setting = certificate.template.settings
start_date = datetime.strftime(certificate.start_date,'%d/%m/%Y')
end_date = datetime.strftime(certificate.start_date,'%d/%m/%Y')
data['text_front'] = setting.replace('<<nome>>',participant.name).replace('<<cpf>>',str(participant.cpf)).replace('<<ch>>',str(certificate.ch)).replace('<<instituicao>>',str(certificate.institution)).replace('<<DataInicio>>',start_date).replace('<<DataFim>>',end_date)
data['cpf'] = participant.cpf
pdf = render_to_pdf('app_certificates/body_front_pdf.html', data)
return HttpResponse(pdf, content_type='application/pdf')
except TypeError as e:
return HttpResponse(e)

Using Pil to store image in a list and retrieve those image in a browser

This question is not a duplicate because I have stored the image address in a dataset and i need to retrieve those images that are present in my folder using a machine learning model, store it in a list and display those images in a browser I am creating a movie recommendation system in flask. I need to display poster image along with the name, but the browser doesn't seem to view the image. Here is my code:
app.py:
from flask import Flask,render_template
from flask import request
from sample import get_title_from_index
from sample import get_poster_from_index
from sample import similar_movies
from flask import jsonify
from PIL import Image
import array as arr
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def predict():
if 'movie_input' in request.form:
movies = similar_movies(request.form['movie_input'])
i=0
print("Top 5 similar movies are:")
e1= []
p1=[]
for element in movies:
e1.insert(0,get_title_from_index(element[0]))
image= Image.open(get_poster_from_index(element[0]))
p1.insert(0,image)
i=i+1
if i>5:
break
else:
e1 = "No movies selected. Please, select something!"
p1 = ""
return render_template('predictor.html', movie=e1,poster=p1)
if __name__ == '__main__':
app.run(debug=True)
predictor.html:
<!doctype html>
<html>
<head>
</head>
<body>
<form method="POST">
<input type="text" name="movie_input" maxlength="500" >
<input type="submit" value="Submit" method="get" >
</form>
<p>
{{movie[0]}}
{{poster[0]}}
</p>
</body>
</html>
sample.py
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
df = pd.read_csv("movies.csv")
def get_title_from_index(index):
return df[df.index == index]["title"].values[0]
def get_index_from_title(title):
return df[df.title == title]["index"].values[0]
def get_poster_from_index(index):
return df[df.index == index]["poster"].values[0]
def combine_features(row):
return row["keywords"]+"" +row["cast"]+""+row["genres"]+""+row["director"]
def similar_movies(movie_input):
features = ['keywords','cast','genres','director']
df["poster"] = df["poster"].fillna("")
for feature in features:
df[feature] = df[feature].fillna("") #filling all NaNs with blank string
df["combined_features"] = df.apply(combine_features,axis=1)
cv = CountVectorizer() #creating new CountVectorizer() object
count_matrix = cv.fit_transform(df["combined_features"])
cosine_sim = cosine_similarity(count_matrix)
movie_index = get_index_from_title(movie_input)
similar_movies = list(enumerate(cosine_sim[movie_index]))
sorted_similar_movies = sorted(similar_movies,key=lambda x:x[1],reverse=True)[1:]
return sorted_similar_movies
The browser view:
browser view
The browser view shows that the image is present but doesn't seems to view it.
dataset view
movie dataset view
folder view
flask folder
Please review my code and let me know the necessary changes.
You can't just output an image file into html. You have you have encode it an put it in an html IMG tag.
If you encode the image data into base64, you can do something like:
{{movie[0]}}
<img src="data:image/png;base64, {{poster[0]}}" />
For encoding the image, see Encoding an image file with base64

Flask upload file to produce curve in Python

I want to be able to upload a file to a web application and have each column of the file plotted against the values in the first column. In this particular example, y and error should be plotted against t, yielding two curves.
t
0.0000
1.0000
1.2300
y
1.2345
0.9871
0.5545
error
1.4E-4
-4.9E-3
8.2E-3
I managed to get the upload part working properly but am lost on how I could use the info from a file to plot a curve.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF_8">
<title>Uploader</title>
</head>
<body>
<h1>Upload your file</h1>
<form id = "upload-form" action = "{{ url_for('upload') }}" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" accept = "file/*" multiple/>
<input type = "submit" value ="upload"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Uploaded</title>
</head>
<body>
Uploaded Successfully
</body>
</html>
import os
from flask import Flask,render_template,request
from bokeh.plotting import figure
from bokeh.io import output_file,show
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
fg = figure(x_axis_label ="x",y_axis_label = "y")
x = [1,2,3,4]
y = [1,2,3,4]
fg.circle(x,y)
#app.route("/")
def index():
return render_template("view.html")
#app.route("/upload", methods=['POST'])
def upload():
target = os.path.join(APP_ROOT,'files/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("file"):
print(file)
filename = file.filename
destination = "/".join([target,filename])
print(destination)
file.save(destination)
lines = file.read().split('\n') # a list, each element is a line
for line in lines:
x_raw, y_raw, error_raw = line.split(' ') # split the line into three, assign them to variabes
x, y, error = float(x_raw), float(y_raw), float(error_raw) # parse each part into a floating point number
return render_template("uploaded.html")
if __name__ == "__main__":
app.run(debug=True)
You can get the contents of a uploaded file as a string without saving it with file.read()
Read file data without saving it in Flask
Then parse the string. If your file were like this:
0.0000 1.2345 1.4E-4
1.0000 0.9871 -4.9E-3
1.2300 0.5545 8.2E-3
You could use this to extract the values:
lines = file.read().split('\n') # a list, each element is a line
for line in line:
x_raw, y_raw, error_raw = line.split(' ') # split the line into three, assign them to variabes
x, y, error = float(x_raw), float(y_raw), float(error_raw) # parse each part into a floating point number
string.split() works like:
>>> "a,b,c;d,e,f".split(';')
['a,b,c', 'd,e,f']

Showing web camera through web interface (Python, CherryPy, OpenCV)

I want to show OpenCV processed image with web interface (made with CherryPy). Code below works fine:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
return data.tostring()
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
However: I would like to embed the image in html so I can (for example) add another image or other data to the same page.
I have tried the following code:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpeg', image)
return """ <html>
<head>
<title>CherryPy static imagl</title>
</head>
<html>
<body>
<img src=" """ + data + """:image/jpeg" />
</body>
</html>"""
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
But this gives the following error:
<img src=" """ + data + """:image/jpeg" />
TypeError: cannot concatenate 'str' and 'numpy.ndarray' objects
Converting the numpy arry to a string using the following code also does not work (it gives no error but displays only characters):
<img src=" """ + data.tostring() + """:image/jpeg" />
Anyone who can give me some more insight? Thanks in advance!
The following code does the trick :)
import cherrypy
import cv2
import base64
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
jpeg_base64 = base64.b64encode(data.tostring())
return """
<html>
<head>
<meta http-equiv="refresh" content="1" />
<title>Cherrypy webcam</title>
</head>
<html>
<body>
<img src='data:image/jpeg;base64,%s' />
<img src='data:image/jpeg;base64,%s' />
</body>
</html>
""" % (jpeg_base64, jpeg_base64)
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
This code displays the same picture two times. and the:
<meta http-equiv="refresh" content="1" />
refreshes the code every second.

Categories

Resources