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 ## Activate the virtual enviroement
Then you need to activate the virtual enviroment. Then you need to activate the virtual enviroment.
- for Bash - for Bash
```bash ```bash
source .venv/bin/activate source .venv/bin/activate
``` ```
- for Fish - for Fish
```bash ```bash
. .venv/bin/activate.fish . .venv/bin/activate.fish
``` ```
--- ---
If executed corectly your *(.venv)* should apear on your terminal If executed corectly your *(.venv)* should apear on your terminal
```bash ```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. - **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). - **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 ## First Run
The firsat run is simple enought. Just execute your *app.py*. Just make sure that your *venv* is active. The firsat run is simple enought. Just execute your *app.py*. Just make sure that your *venv* is active.
```bash ```bash
@ -127,10 +125,8 @@ Hereyou can see as before the main route *(/)*
def index(): def index():
return "Welcome" return "Welcome"
``` ```
--- ---
## URL proccessors
## url proccessors
We can also use url proccessors to get something that we have typed on the url. 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) In this case the url to visit would be [http://localhost:5000/greet/kerem](http://localhost:5000/greet/kerem)
```python ```python
@ -138,18 +134,14 @@ In this case the url to visit would be [http://localhost:5000/greet/kerem](http:
def greet(name): def greet(name):
return f"Hello {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) 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 ```python
@app.route('/add/<int:number1>/<int:number2>') @app.route('/add/<int:number1>/<int:number2>')
def add(number1, number2): def add(number1, number2):
return f'{number1} + {number2} = {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 Now to do generate some responses. Here you can use [curl](https://curl.se/) so see exactly what is happening
```python ```python
#We can also return some responses (like 404 page not found and co) #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 Content-Length: 11
Connection: close Connection: close
``` ```
--- ---
## Methods
## Methodes This is the way to allow or block some [Methods](https://www.w3schools.com/tags/att_method.asp).
This is the way to allow or block some [Methodes](https://www.w3schools.com/tags/att_method.asp).
```python ```python
@app.route('/test_methodes', methods=['GET', 'POST']) @app.route('/test_methodes', methods=['GET', 'POST'])
def test_methodes(): def test_methodes():
@ -186,10 +176,9 @@ def test_methodes():
else: else:
return f"You will never see this message\n" return f"You will never see this message\n"
``` ```
--- ---
## Parameters
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. 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 ```python
#Handle parameters : #Handle parameters :
@app.route('/handle_url_params') @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) # 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. 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* let's create the *directory*
```bash ```bash
@ -225,9 +214,7 @@ Let's declare it in our code. *template_folder* take the source of *app.py* as s
```python ```python
app = Flask(__name__, template_folder='templates') app = Flask(__name__, template_folder='templates')
``` ```
--- ---
## Using 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. 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) 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. 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/). This is thnaks to [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/). Let's see how it works.
Let's see how it works.
---
## HTML & Jinja ## HTML & Jinja
Now let's have a look to `index.html` herre we can now se some *Jinja* templates funtionlaities. Now let's have a look to `index.html` herre we can now se some *Jinja* templates funtionlaities.
```HTML ```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. *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 `%}`. 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>`. - They can also be used inline like: `<li {%if item == 20 %} style="color: blue" {%endif%} >{{ item }}</li>`.
---
## Extend Templates ## 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. 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*. 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(): def other():
return render_template('other.html') return render_template('other.html')
``` ```
--- ---
## Jinja [Filters](https://jinja.palletsprojects.com/en/3.0.x/templates/#filters) ## 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. 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.
@ -393,7 +374,9 @@ def reverse_string(s):
``` ```
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* Redirections can be tricky but thankfully Flask has a way od dynamic *redirection* wich takes a *function* as *argument*
```PYTHON ```PYTHON
@app.route('/redirect_endpoint') @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* - 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')` - 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. - 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 pandas as pd
import os import os
import uuid import uuid
@ -56,5 +56,18 @@ def convert_csv_two():
def download(filename): def download(filename):
return send_from_directory('downloads', filename, download_name='result.csv') 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__': if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True) app.run(host='0.0.0.0', port=5000, debug=True)

@ -28,4 +28,26 @@
<input type="submit" value="upload File"> <input type="submit" value="upload File">
</form> </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 %} {% endblock %}

Loading…
Cancel
Save