Starting video 4

master
Kerem Yollu 1 year ago
parent 0da1c4bc7e
commit ce6b498a7f

@ -0,0 +1,73 @@
from flask import Flask, request, make_response, Response, render_template, redirect, url_for, send_from_directory, jsonify
import pandas as pd
import os
import uuid
app = Flask(__name__, template_folder='templates')
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username == 'kynsight' and password == 'pass':
return 'Success'
else:
return 'Failure'
@app.route('/file_upload', methods=['GET', 'POST'])
def file_upload():
file = request.files.get('file')
if file.content_type == 'text/plain':
return file.read().decode()
elif file.content_type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' or file.content_type == 'application/vnd.ms-excel':
df = pd.read_excel(file)
return df.to_html()
@app.route('/convert_csv', methods=['GET', 'POST'])
def convert_csv():
file = request.files.get('file')
df = pd.read_excel(file)
response = Response(
df.to_csv(),
mimetype = 'text/csv',
headers={'Content-Disposition': 'attachement; filename=result.csv'}
)
return response
@app.route('/convert_csv_two', methods=['GET', 'POST'])
def convert_csv_two():
file = request.files.get('file')
df = pd.read_excel(file)
if not os.path.exists('downloads'):
os.makedirs('downloads')
filename = f'{uuid.uuid4()}.cvs'
df.to_csv(os.path.join('downloads', filename))
return render_template('download.html', filename=filename)
@app.route('/download/<filename>', methods=['GET', 'POST'])
def download(filename):
return send_from_directory('downloads', filename, download_name='result.csv')
@app.route('/handle_post', methods=['GET', 'POST'])
def handle_post():
greeting = request.json.get('greeting')
name = request.json.get('name')
with open('file.txt','w') as f:
f.write(f'{greeting}, {name}')
return jsonify({'message': 'Successfully written!'})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)

@ -13,13 +13,13 @@ python3 -m venv .venv
## Activate the virtual enviroement
Then you need to activate the virtual enviroment.
- for Bash
```bash
source .venv/bin/activate
```
```bash
source .venv/bin/activate
```
- for Fish
```bash
. .venv/bin/activate.fish
```
```bash
. .venv/bin/activate.fish
```
---
If executed corectly your *(.venv)* should apear on your terminal
```bash
@ -91,9 +91,7 @@ In the *run()* funtion there are some main parameters that needs to be defined t
- **port** ([*int*](https://docs.python.org/3/library/functions.html#int)* | **None*) the port of the webserver. Defaults to *5000* or the port defined in the *SERVER_NAME* config variable if present.
- **debug** ([*bool*](https://docs.python.org/3/library/functions.html#bool)* | **None*) if given, enable or disable debug mode. See [debug](https://flask.palletsprojects.com/en/2.3.x/api/#flask.Flask.debug).
---
## First Run
The firsat run is simple enought. Just execute your *app.py*. Just make sure that your *venv* is active.
```bash
@ -127,10 +125,8 @@ Hereyou can see as before the main route *(/)*
def index():
return "Welcome"
```
---
## url proccessors
## URL proccessors
We can also use url proccessors to get something that we have typed on the url.
In this case the url to visit would be [http://localhost:5000/greet/kerem](http://localhost:5000/greet/kerem)
```python
@ -138,18 +134,14 @@ In this case the url to visit would be [http://localhost:5000/greet/kerem](http:
def greet(name):
return f"Hello {name}"
```
---
Variables given to the url can also be *typed* here as integers. This allows us to do some advanced operations. In this case the url to visit would be [http://localhost:5000/add/20/10](http://localhost:5000/add/20/10)
```python
@app.route('/add/<int:number1>/<int:number2>')
def add(number1, number2):
return f'{number1} + {number2} = {number1+number2}'
```
---
## Responses
Now to do generate some responses. Here you can use [curl](https://curl.se/) so see exactly what is happening
```python
#We can also return some responses (like 404 page not found and co)
@ -171,11 +163,9 @@ content-type: application/octet-stream
Content-Length: 11
Connection: close
```
---
## Methodes
This is the way to allow or block some [Methodes](https://www.w3schools.com/tags/att_method.asp).
## Methods
This is the way to allow or block some [Methods](https://www.w3schools.com/tags/att_method.asp).
```python
@app.route('/test_methodes', methods=['GET', 'POST'])
def test_methodes():
@ -186,10 +176,9 @@ def test_methodes():
else:
return f"You will never see this message\n"
```
---
You have surely seen some Parametes embedde in liks like *?user=bgfdrt56+pass=Rtrssdf*. Flask alows some asy maniputation of those parameters. To test this : [http://localhost:5000/handle_url_params?greeting=hello&name=kerem](http://localhost:5000/handle_url_params?greeting=hello&name=kerem). If there was a mistmatch you would get the Error message instead.
## Parameters
You have surely seen some Parametes embedded in liks like *?user=bgfdrt56+pass=Rtrssdf*. Flask alows some asy maniputation of those parameters. To test this : [http://localhost:5000/handle_url_params?greeting=hello&name=kerem](http://localhost:5000/handle_url_params?greeting=hello&name=kerem). If there was a mistmatch you would get the Error message instead.
```python
#Handle parameters :
@app.route('/handle_url_params')
@ -205,7 +194,7 @@ def handle_url_params():
---
# Flask HTML files And [TEMPLATES](https://flask.palletsprojects.com/en/3.0.x/tutorial/templates/) [YouTube](https://youtu.be/w6Ui_DVxluc?si=B2JshnjVMu3DWcBC)
## Indicate that we use Templates
## Declare that we use Templates
To indicate that we will use *templates* first we need to create a *directory* containing those tmeplates and second we need to *reference* it in our code.
let's create the *directory*
```bash
@ -225,9 +214,7 @@ Let's declare it in our code. *template_folder* take the source of *app.py* as s
```python
app = Flask(__name__, template_folder='templates')
```
---
## Using Templates
The [`render_template()`](https://flask.palletsprojects.com/en/2.3.x/templating/#) let's use use tem when returning the content of the page.
@ -240,12 +227,9 @@ def index():
return render_template('index.html', value=myval, result=myres, list=mylist)
```
Now this allows us to have a huge flexibility that HTML doesn't otherwise allow.
This is thnaks to [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/).
Let's see how it works.
---
This is thnaks to [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/). Let's see how it works.
## HTML & Jinja
Now let's have a look to `index.html` herre we can now se some *Jinja* templates funtionlaities.
```HTML
@ -275,7 +259,7 @@ Now let's have a look to `index.html` herre we can now se some *Jinja* templates
*Jinja* Allows us to use these kind of functions : `{% for item in list %}` that are ususaly inpossible wiht HTML.
All *Jinja* Functions starts with `{%` and ends with `%}`.
- They can also be used inline like: `<li {%if item == 20 %} style="color: blue" {%endif%} >{{ item }}</li>`.
---
## Extend Templates
We cna extend templates to other templates. What does this bring us ? Let's say we want ta have the *same header* on *multiple pages* we can use a template with the header and only add an *content* *BLOCK* onto this template.
In *templeates* directory we can now create a base html file let's call it *base.htm* and two pages that extends on it *index.html* and *other.html*.
@ -357,10 +341,7 @@ but here we need to add a route to this page at *app.py*
def other():
return render_template('other.html')
```
---
## Jinja [Filters](https://jinja.palletsprojects.com/en/3.0.x/templates/#filters)
Filters that python uses lin `.uppercase` can't be used in Jinja. There are some filters taht already exists but most importnatly we can create our own filters.
@ -391,9 +372,11 @@ We of course need to define `reverse_string` in *app.py* as follows :
def reverse_string(s):
return s[::-1]
```
you can see that we use a speciel decorator named [template_filter](https://tedboy.github.io/flask/generated/generated/flask.Flask.template_filter.html) to declare our custom filters.
you can see that we use a speciel decorator named [template_filter](https://tedboy.github.io/flask/generated/generated/flask.Flask.template_filter.html) to declare our custom filters.
---
## Redirection
# Redirection
Redirections can be tricky but thankfully Flask has a way od dynamic *redirection* wich takes a *function* as *argument*
```PYTHON
@app.route('/redirect_endpoint')
@ -450,3 +433,115 @@ So what is going on here ?
- If the *Methode* is *POST* we collect the information filler in *form* sent by pressing *submit*
- We get collect the *information* by *referencing* form items by their *name* attribute : `request.form.get('username')`
- Then we can put these infiormation in varibales and use them as we please.
---
# Uploading & downloading files
Be careful here are some notions that are not related to Flask or Jinja. Like [Pandas](https://pandas.pydata.org/) for excel manipulation and [os](https://docs.python.org/3/library/os.html) of opperating system functions. Nevertheless this is a very important topic with widely used applications for website.
## Uploading a file
Here is the *File Upload form* located in *index.html* the most important element to know are :
- [enctype="multipart/form-data"](https://www.w3schools.com/tags/att_form_enctype.asp) Used while uploading files
- [accept=](https://www.w3schools.com/tags/att_input_accept.asp)"[media-types](http://www.iana.org/assignments/media-types/media-types.xhtml)" do define which types of files are allowed.
```html
<h1>File Upload</h1>
<form method="POST" action="{{ url_for('file_upload') }}" enctype="multipart/form-data">
<input type="file" name="file" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" ><br>
<input type="submit" value="upload File">
</form>
```
Wiht the `action="{{ url_for('file_upload') }}"` we go back to our *app.py* funtion *def file_upload():* where we treat this information. Where we do nothing else then to read the file and print his output.
- If it's a *Text* file we put directly it's output
- If it's a *Excel* file we read the file using pandas `df = pd.read_excel(file)` and return the result as html table using `return df.to_html()`
```python
import pandas as pd
@app.route('/file_upload', methods=['GET', 'POST'])
def file_upload():
file = request.files.get('file')
if file.content_type == 'text/plain':
return file.read().decode()
elif file.content_type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' or file.content_type == 'application/vnd.ms-excel':
df = pd.read_excel(file)
return df.to_html()
```
---
## Download a file directly
Here is the *File Upload form* located in *index.html* tnothing mroe to know then the previous example:
```html
<h1>Convert To CSV</h1>
<form method="POST" action="{{ url_for('convert_csv') }}" enctype="multipart/form-data">
<input type="file" name="file" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" ><br>
<input type="submit" value="upload File">
</form>
```
Wiht the `action="{{ url_for('convert_csv') }}"` we go back to our *app.py* funtion *def convert_csv():* where we convert the excel into csv but also directly donwload the ouput. It is a specific example and we don't need to waste too much time on it as there is, in my opignon a much better way to do this.
```python
@app.route('/convert_csv', methods=['GET', 'POST'])
def convert_csv():
file = request.files.get('file')
df = pd.read_excel(file)
response = Response(
df.to_csv(),
mimetype = 'text/csv',
headers={'Content-Disposition': 'attachement; filename=result.csv'}
)
return response
```
---
## Download a file thourgh a directory
Again nothing special to note here, same a the ones before.
```html
<h1>Convert To CSV Two</h1>
<form method="POST" action="{{ url_for('convert_csv_two') }}" enctype="multipart/form-data">
<input type="file" name="file" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" ><br>
<input type="submit" value="upload File">
</form>
```
Wiht the `action="{{ url_for('convert_csv_two') }}"` we go back to our *app.py* funtion *def convert_csv_two():*, convert the file to csv and make it redy for download:
- `os.makedirs('downloads')` we create a donwload directory
- `filename = f'{uuid.uuid4()}.cvs'` we give the file a unique name
- `df.to_csv(os.path.join('downloads', filename))`we convert the file into csv and register in *downloads* with his*filename*
- `return render_template('download.html', filename=filename)` we return the *download.html* page with *filename* as argument
```python
@app.route('/convert_csv_two', methods=['GET', 'POST'])
def convert_csv_two():
file = request.files.get('file')
df = pd.read_excel(file)
if not os.path.exists('downloads'):
os.makedirs('downloads')
filename = f'{uuid.uuid4()}.cvs'
df.to_csv(os.path.join('downloads', filename))
return render_template('download.html', filename=filename)
```
for that to work we need to create the *download.html* in *templates* directory:
- `href="{{ url_for('download', filename=filename) }}"`Directs the request to `def download(filename):` function which generates the download proccess
```html
{% extends "base.html" %}
{% block title %}Download Page{% endblock %}
{% block content %}
<h1>Download {{ filename }}</h1>
<a href="{{ url_for('download', filename=filename) }}"> Donwload </a>
{% endblock %}
```
and aso create a new route for *download* in *app.py*:
- `@app.route('/download/<filename>'` the route has de name route to */download* but allso the argument *<filename>*
- `send_from_directory('downloads', filename, download_name='result.csv')` alows us to *send* the file *downloads* directory and *rename* it at the same time
```python
@app.route('/download/<filename>', methods=['GET', 'POST'])
def download(filename):
return send_from_directory('downloads', filename, download_name='result.csv')
```
---
# JS/json Request for live update
todo if needed. for now i am nto so shure.
---
# Static Files & Integrating Bootstrap

@ -1,4 +1,4 @@
from flask import Flask, request, make_response, Response, render_template, redirect, url_for, send_from_directory
from flask import Flask, request, make_response, Response, render_template, redirect, url_for, send_from_directory, jsonify
import pandas as pd
import os
import uuid
@ -56,5 +56,18 @@ def convert_csv_two():
def download(filename):
return send_from_directory('downloads', filename, download_name='result.csv')
@app.route('/handle_post', methods=['GET', 'POST'])
def handle_post():
greeting = request.json.get('greeting')
name = request.json.get('name')
with open('file.txt','w') as f:
f.write(f'{greeting}, {name}')
return jsonify({'message': 'Successfully written!'})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)

@ -27,5 +27,27 @@
<input type="file" name="file" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" ><br>
<input type="submit" value="upload File">
</form>
<h1>JS JSON request</h1>
<button id="post_button"> Send Post </button>
<script type="text/javascript">
const postButton = document.getElementById('post_button');
const jsonData = {name : 'Mike', greeting: 'Hello'}
postButton.addEventListener('click', () => {
fetch('{{ url_for("handle_post") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(jsonData)
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch((error) => {
console.error('Error', error)
});
});
</script>
{% endblock %}

Loading…
Cancel
Save