@ -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)
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
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*
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.
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()`
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.
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
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