Add form and Add search
This commit is contained in:
parent
a3f3b49b2c
commit
e26eb50582
21
README.md
21
README.md
@ -12,7 +12,7 @@
|
||||
|
||||
[wallaviso.com](http://wallaviso.com)
|
||||
|
||||
## Run
|
||||
## Run (Ejecutar)
|
||||
|
||||
[EN] For the impatient, you can play with the finished exercise. You should download the code and execute the following commands.
|
||||
|
||||
@ -30,3 +30,22 @@ python3 app.py
|
||||
[EN] Then open in your favorite browser, which will possibly be the fantastic Firefox, a new tab with [http://127.0.0.1:5000](http://127.0.0.1:5000)
|
||||
|
||||
[ES] Después abrir en tu navegador favorito, que posiblemente será el fantástico Firefox, una pestaña nueva con [http://127.0.0.1:5000](http://127.0.0.1:5000)
|
||||
|
||||
## Workshop (Taller)
|
||||
|
||||
### Part 1 - Flask Core y Search (Parte 1 - Nucleo de Flask y Buscador) 50 min
|
||||
|
||||
### Break (Descanso) - 10 min
|
||||
|
||||
[EN] We debug bugs and prepare for the next point.
|
||||
[ES] Depuramos bugs y nos preparamos para el siguiente punto.
|
||||
|
||||
### Part 2 - Databases and CRUD with Flask (Bases de datos y CRUD elementos con Flask)
|
||||
|
||||
### Break (Descanso) - 10 min
|
||||
|
||||
[EN] We take air for the last part. Otherwise, we make as we go to the bathroom and do not come back.
|
||||
[ES] Cogemos aire para la última parte. En caso contrario, hacemos como que vamos al baño y nos piramos.
|
||||
|
||||
|
||||
### Part 3 - Sending emails with new items (Envío de emails con nuevos elementos)
|
38
app.py
38
app.py
@ -1,10 +1,40 @@
|
||||
from flask import Flask, render_template
|
||||
from flask import Flask, render_template, request
|
||||
from forms import SearchForm
|
||||
# Get data Wallapop
|
||||
import json
|
||||
from urllib3 import PoolManager
|
||||
import urllib.parse
|
||||
|
||||
# Flask
|
||||
app = Flask(__name__)
|
||||
app.config['DEBUG'] = True
|
||||
app.config['SECRET_KEY'] = 'mi secreto'
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def buscador():
|
||||
form = SearchForm()
|
||||
results = None
|
||||
if form.validate_on_submit():
|
||||
name = form.name.data
|
||||
price_max = form.price_max.data or ''
|
||||
|
||||
# Search in Wallapop
|
||||
http = PoolManager()
|
||||
url_api = 'http://es.wallapop.com/rest/items?minPrice=&maxPrice={price_max}&dist=&order=creationDate-des&lat=41.398077&lng=2.170432&kws={kws}'.format(
|
||||
kws=urllib.parse.quote(name, safe=''),
|
||||
price_max=price_max
|
||||
)
|
||||
results = http.request('GET', url_api)
|
||||
results = json.loads(
|
||||
results.data.decode('utf-8')
|
||||
)
|
||||
results = results['items']
|
||||
return render_template('items/buscador.html', form=form, results=results)
|
||||
|
||||
@app.route('/programadas')
|
||||
def programadas():
|
||||
return render_template('items/programadas.html')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('items/buscador.html')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
8
forms.py
Normal file
8
forms.py
Normal file
@ -0,0 +1,8 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, IntegerField
|
||||
from wtforms.validators import DataRequired, Length, NumberRange, Optional
|
||||
|
||||
|
||||
class SearchForm(FlaskForm):
|
||||
name = StringField('Nombre', [Length(min=1, max=100, message='Es demasiado largo'), DataRequired(message='Campo obligatorio')])
|
||||
price_max = IntegerField('Precio', [NumberRange(1, message='No puede ser inferior a 1'), Optional()])
|
@ -0,0 +1,3 @@
|
||||
Flask==0.12.2
|
||||
Flask-WTF==0.14.2
|
||||
urllib3==1.22
|
@ -1,13 +1,46 @@
|
||||
{% extends 'layouts/master.html' %}
|
||||
{% set active_page = "buscador" %}
|
||||
{% block title %}Buscador{% endblock %}
|
||||
{% block body %}
|
||||
<h1>Buscador</h1>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<form >
|
||||
<input type="text" id="nombre" class="form-control" name="nombre" placeholder="Buscar...">
|
||||
<input type="submit" class="form-control" value="Buscar">
|
||||
<form method="post">
|
||||
{{ form.csrf_token }}
|
||||
{% for input in form %}
|
||||
{% if input.type != 'CSRFTokenField' %}
|
||||
<div class="form-group">
|
||||
{# Label #}
|
||||
{{ input.label }}
|
||||
{# Input #}
|
||||
{{ input(class="form-control") }}
|
||||
{# Errors #}
|
||||
{% if input.errors %}
|
||||
<div class="has-error">
|
||||
{% for error in input.errors %}
|
||||
<label class="help-block">
|
||||
{{ error }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<input type="submit" class="btn btn-primary" value="Buscar">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% if results %}
|
||||
<table class="table">
|
||||
{% for item in results %}
|
||||
<tr>
|
||||
<td><img class="img-responsive" src="{{ item.pictureURL }}" alt="{{ item.title }}"></td>
|
||||
<td>{{ item.title }}</td>
|
||||
<td>{{ item.price }}</td>
|
||||
<td><a href="#" class="btn btn-success">+</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
6
templates/items/programadas.html
Normal file
6
templates/items/programadas.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% extends 'layouts/master.html' %}
|
||||
{% set active_page = "programadas" %}
|
||||
{% block title %}Programadas{% endblock %}
|
||||
{% block body %}
|
||||
<h1>Programadas</h1>
|
||||
{% endblock %}
|
@ -8,6 +8,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<li role="presentation" {% if active_page == "buscador" %}class="active"{% endif %}><a href="{{ url_for('buscador') }}">Buscador</a></li>
|
||||
<li role="presentation" {% if active_page == "programadas" %}class="active"{% endif %}><a href="{{ url_for('programadas') }}">Programadas</a></li>
|
||||
</ul>
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user