Project 4: Movie Watchlist: Render a WTForms form with Jinja and HTML (+174, -0)
routes.py (+13, -0)
From:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/start/movie_library/routes.py
To:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/routes.py
index 3d58ec5..b3bb925 100644
--- a/curriculum/section14/lectures/07_render_wtform_with_jinja_macros/start/movie_library/routes.py
+++ b/curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/routes.py
@@ -5,6 +5,7 @@ from flask import (
session,
request,
)
+from movie_library.forms import MovieForm
pages = Blueprint(
@@ -20,6 +21,18 @@ def index():
)
+@pages.route("/add", methods=["GET", "POST"])
+def add_movie():
+ form = MovieForm()
+
+ if request.method == "POST":
+ pass
+
+ return render_template(
+ "new_movie.html", title="Movies Watchlist - Add Movie", form=form
+ )
+
+
@pages.get("/toggle-theme")
def toggle_theme():
current_theme = session.get("theme")
forms.css (+115, -0)
From:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/static/css/forms.css
To:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/static/css/forms.css
new file mode 100644
index 0000000..c6e3132
--- /dev/null
+++ b/curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/static/css/forms.css
@@ -0,0 +1,115 @@
+.form {
+ margin: 0 auto;
+ max-width: 30rem;
+ border: var(--border);
+ font-size: 1.2rem;
+
+ /* An explicit background is required here, as it's actually transparent by default, and we
+ don't want to see the shadow element behind */
+ background: var(--background-color);
+
+ /* This shadow is separated from the edges by 0.75rem, and shrunk by 0.2rem on the
+ top and bottom. */
+ box-shadow: 0.75rem 0.75rem 0 -0.2rem var(--accent-colour);
+}
+
+.form__container {
+ padding: 2.5rem 1.5rem 1.5rem 1.5rem;
+}
+
+/* The following media queries allow for more padding inside the form as the window
+ size increases */
+@media screen and (min-width: 24.75em) {
+ .form__container {
+ padding-left: 2rem;
+ }
+}
+
+@media screen and (min-width: 30em) {
+ .form__container {
+ padding-left: 2.5rem;
+ }
+}
+
+.form__group {
+ /* Surrounds the label and input fields, placing the label above the input */
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 1.5rem;
+}
+
+.form__label {
+ margin-bottom: 0.5rem;
+}
+
+.form__field {
+ /* Removes the border and the outline highlight when the text field is in focus */
+ outline: none;
+ border: none;
+
+ /* Re-adds a bottom border which will be replaces when the field is in focus. This
+ is going to prevent any jumping when we add the border later */
+ border-bottom: 3px solid #fff;
+
+ /* We have to be explicit about our text fields inheriting font properties */
+ font-size: inherit;
+ font-family: inherit;
+
+ padding: 0.75rem 0.5rem;
+ background: var(--background-color);
+}
+
+/* When the field is in focus, we change the border colour at the bottom to the accent colour */
+.form__field:focus {
+ border-bottom: var(--border);
+}
+
+.form__small {
+ font-size: 0.83rem;
+ color: var(--text-muted);
+}
+
+.form__link {
+ text-decoration: none;
+ color: var(--accent-colour);
+}
+
+.form__link:hover {
+ color: #d05656;
+}
+
+.form__error {
+ margin-top: 0.5rem;
+}
+
+.form__error,
+.form__flash {
+ display: block;
+ padding: 0.5rem;
+ color: var(--text);
+}
+
+.form__error,
+.form__flash--danger {
+ background: var(--accent-colour);
+}
+
+.form__flash {
+ margin: 0.5rem;
+}
+
+.form__flash--success {
+ background: var(--accent-colour-2);
+}
+
+/* Styles specific to the form buttons */
+.button--form {
+ margin: 2rem 0 0 auto;
+ padding: 0.75rem 3rem;
+ border: none;
+ background: var(--background-color);
+}
+
+.button--form:hover {
+ background: var(--background-color-hover);
+}
fields.jinja2 (+22, -0)
From:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/macros/fields.jinja2
To:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/macros/fields.jinja2
new file mode 100644
index 0000000..e96b72a
--- /dev/null
+++ b/curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/macros/fields.jinja2
@@ -0,0 +1,22 @@
+{% macro render_text_field(field) %}
+<div class="form__group">
+ {{ field.label(class_="form__label") }}
+ {{ field(class_="form__field")}}
+
+ {%- for error in field.errors %}
+ <span class="form__error">{{ error }}</span>
+ {% endfor %}
+</div>
+{% endmacro %}
+
+
+{% macro render_area_field(field) %}
+<div class="form__group">
+ {{ field.label(class_="form__label") }}
+ {{ field(rows=4, class_="form__field", style="resize: none") }}
+
+ {%- for error in field.errors %}
+ <span class="form__error">{{ error }}</span>
+ {% endfor %}
+</div>
+{% endmacro %}
new_movie.html (+24, -0)
From:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/new_movie.html
To:
curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/new_movie.html
new file mode 100644
index 0000000..87514c2
--- /dev/null
+++ b/curriculum/section14/lectures/07_render_wtform_with_jinja_macros/end/movie_library/templates/new_movie.html
@@ -0,0 +1,24 @@
+{% from "macros/fields.html" import render_text_field %}
+
+{% extends "layout.html" %}
+
+{%- block head_content %}
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/forms.css') }}" />
+{% endblock %}
+
+{% block main_content %}
+
+ <form name="add_movie" method="post" novalidate class="form">
+ <div class="form__container">
+ {{ form.hidden_tag() }}
+ {{ render_text_field(form.title) }}
+ {{ render_text_field(form.director) }}
+ {{ render_text_field(form.year) }}
+
+ <div>
+ {{ form.submit(class_="button button--form") }}
+ </div>
+ </div>
+ </form>
+
+{% endblock %}