-
-
Save codecademydev/3e7515a2ca6f5b665aca39bf27747d3d to your computer and use it in GitHub Desktop.
Codecademy export
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask import Flask, render_template, request, redirect, url_for | |
from locations import Locations | |
from forms import AddLocationForm | |
app = Flask(__name__) | |
app.config['SECRET_KEY'] = 'SECRET_PROJECT' | |
# Note that app.config['SECRET_KEY'] is already set. Remember this is necessary to protect against a Cross-Site Request Forgery attack | |
visit = Locations() | |
categories = {"recommended": "Recommended", "tovisit": "Places To Go", "visited": "Visited!!!", } | |
UP_ACTION = "\u2197" | |
DEL_ACTION = "X" | |
@app.route("/<category>", methods=["GET", "POST"]) | |
def locations(category): | |
locations = visit.get_list_by_category(category) | |
## Check the request for form data and process by testing requests method attribute | |
if request.method == "POST": | |
[(name, action)] = request.form.items() | |
if action == UP_ACTION: | |
visit.moveup(name) | |
elif action == DEL_ACTION: | |
visit.delete(name) | |
## Return the main template with variables | |
return render_template("locations.html", category=category, categories=categories, locations=locations, add_location=AddLocationForm()) | |
@app.route("/add_location", methods=["POST"]) | |
def add_location(): | |
## Validate and collect the form data | |
add_form = AddLocationForm(csrf_enabled = False) | |
if add_form.validate_on_submit(): | |
# Remember to use .data extension and reference form to transfer the data! | |
name=add_form.name.data | |
description=add_form.description.data | |
category=add_form.category.data | |
visit.add(name, description, category) | |
## Redirect to locations route function | |
return redirect(url_for("locations", category=category, _external=True, _scheme="https")) | |
@app.route("/") | |
def index(): | |
## Redirect to locations route function | |
return redirect(url_for("locations", category="recommended", _external=True, _scheme="https")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<link rel="stylesheet" href="../static/styles.css"> | |
<title>Where To Go</title> | |
</head> | |
<body> | |
{% block content %} | |
{% endblock %} | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Petronas Twin Towers | World's tallest twin towers | recommended | |
---|---|---|---|
Jalan Alor | Street for delicious food | recommended | |
Perdana Botanical Garden | Green oasis in the city | tovisit | |
Islamic Arts Museum | Large open-plan museum with four levels | visited |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask_wtf import FlaskForm | |
from wtforms import StringField, SubmitField, TextAreaField, RadioField | |
from wtforms.validators import DataRequired | |
class FieldsRequiredForm(FlaskForm): | |
"""Require radio fields to have content. This works around the bug that WTForms radio fields don't honor the `DataRequired` or `InputRequired` validators. | |
Note: Provided in forms.py is a new form class, FieldsRequiredForm, that inherits from FlaskForm. This new type of form will allow us to require data for radio button form fields. See programming language below ⬇️ ⬇️ ⬇️ | |
""" | |
class Meta: | |
def render_field(self, field, render_kw): | |
if field.type == "_Option": | |
render_kw.setdefault("required", True) | |
return super().render_field(field, render_kw) | |
categories = [("recommended","Recommended"), ("tovisit", "Places To Go"), ("visited", "Visited!!!")] | |
## Create Form Here | |
class AddLocationForm(FieldsRequiredForm): | |
name = StringField("Location Name", validators=[DataRequired()]) | |
description = TextAreaField("Location Description", validators=[DataRequired()]) | |
category = RadioField("Category", choices=categories) | |
submit= SubmitField("Add Location") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- extend from "base.html" here --> | |
{% extends "base.html" %} | |
{% block content %} | |
<!-- begin block content here --> | |
<!-- NOTE! category is not in quotes below! --> | |
<h1>{{ categories[category] }}</h1> <!-- insert category here --> | |
<div class="navbar"> | |
<!-- begin for loop here --> | |
<!-- REMEMBER! items() method returns a "view object" containing the key-value pairs of the dictionary, as tuples in a list. --> | |
{% for category, label in categories.items() %} | |
<!-- NOTE! label display value is in double brackets below --> | |
<a href="{{category}}">{{label}}</a> <!-- set attribute and text here --> | |
<!-- end for loop here --> | |
{% endfor %} | |
</div> | |
<table> | |
<colgroup> | |
<col style="width: 20%"> | |
<col style="width: 70%"> | |
<col style="width: 10%"> | |
</colgroup> | |
<tbody class="loctable"> | |
<!-- begin for loop here --> | |
{% for location in locations %} | |
<tr> | |
<!-- NOTE! no paraenthesis needed after . name or .description --> | |
<td class="loc">{{ location.name}}</td> <!-- insert location name here --> | |
<td class="desc">{{ location.description}}</td><!-- insert location description here --> | |
<!-- '''NOTE! Double curly delimiters needed for variable assignment and quotes around all attributes but no commas!''' --> | |
<td class="btns"><input type="submit" name="{{location.name}}" value="Submit"> | |
<!-- start if statement here --> | |
{% if location.category in ["recommended", "tovisit"] %} | |
<form method="POST"> | |
<input type="submit" class="up" name="Move Up" value=↗> <!-- set name attribute here --> | |
<input type="submit" class="del" name="Delete" value="X"> <!-- set name attribute here --> | |
</form> | |
<!-- end if statement here --> | |
{% endif %} | |
</td> | |
</tr> | |
<!-- end for loop here --> | |
{% endfor %} | |
</tbody> | |
</table> | |
<form class="addform" action="url_for(add_location)" method="POST"> <!-- set action attribute here --> | |
<!-- call hidden_tag() here --> | |
<!-- Be sure to: | |
Use url_for() inside double quotes | |
Use single quotes for the route function name --> | |
{{ add_location.hidden_tag() }} | |
<table> | |
<colgroup> | |
<col style="width: 40%"> | |
<col style="width: 40%"> | |
<col style="width: 20%"> | |
</colgroup> | |
<tbody> | |
<tr> | |
<!-- .label attribute gives the field descriptor --> | |
<td>{{ add_location.name.label }}</td> <!-- insert location name label here --> | |
<td>{{ add_location.description.label }}</td> <!-- insert location description label here --> | |
<td>{{ add_location.category.label }}</td> <!-- insert location category label here --> | |
</tr> | |
<tr> | |
<td>{{ add_location.name() }}</td> <!-- insert add_location name here --> | |
<td>{{ add_location.description() }}</td> <!-- insert add_location description here --> | |
<td> | |
<!-- begin for loop here --> | |
{% for button in add_location.category %} | |
<!-- Note! use "button" iteration variable's .label to name options --> | |
<div>{{button()}}{{button.label}}</div> <!-- insert button here -- | |
<!-- end for loop here --> | |
{% endfor %} | |
</td> | |
</tr> | |
<tr> | |
<!-- NOTE! NOT using <td class="btns"><input type="submit" ... to create button also NOTE double curly brackets seems to break through comment --> | |
<td> {{ add_location.submit() }} </td> <!-- insert submit here --> | |
</tr> | |
</tbody> | |
</table> | |
</form> | |
<!-- end block content here --> | |
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import csv | |
class Locations: | |
def __init__(self): | |
self.locations = [] | |
self.load_data() | |
def add(self, name, description, category): | |
if name is not None and description is not None and category is not None: | |
location = Location(name, description, category) | |
self.locations.append(location) | |
def get_index_by_name(self, name): | |
for i, location in enumerate(self.locations): | |
if location.name == name: | |
return i | |
def get_list_by_category(self, category): | |
locs = [] | |
for i, location in enumerate(self.locations): | |
if location.category == category: | |
locs.append(location) | |
return locs | |
def delete(self, name): | |
i = self.get_index_by_name(name) | |
self.locations.pop(i) | |
def moveup(self, name): | |
i = self.get_index_by_name(name) | |
if self.locations[i].category == "recommended": | |
self.locations[i].category = "tovisit" | |
elif self.locations[i].category == "tovisit": | |
self.locations[i].category = "visited" | |
def load_data(self): | |
with open("data.csv", "r") as csvfile: | |
locations = csv.reader(csvfile) | |
for row in locations: | |
self.add(row[0], row[1], row[2]) | |
def __repr__(self): | |
for location in self.locations: | |
print(f'{location.name} - {location.description} - {location.category}') | |
class Location: | |
def __init__(self, name, description, category): | |
self.name = name | |
self.description = description | |
self.category = category | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment