diff --git a/app.py b/app.py index 68bedb2..c70b6a6 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,15 @@ from flask import Flask, render_template from blueprint.Login import bp_login +from blueprint.error import bp_error +# 创建Flask应用程序实例 app = Flask(__name__) -app.register_blueprint(bp_login) +app.register_blueprint(bp_login, url_prefix='/login') +app.register_blueprint(bp_error) + + +# 配置Flask应用程序实例 +app.config['SECRET_KEY'] = 'Myth wky' @app.route('/') @@ -10,15 +17,6 @@ def index(): return render_template('index.html') -@app.errorhandler(404) -def page_not_found(e): - return render_template('404.html'), 404 - - -@app.errorhandler(500) -def internal_server_error(e): - return render_template('500.html'), 500 - - if __name__ == '__main__': + DEBUG = True app.run() diff --git a/blueprint/Login.py b/blueprint/Login.py index f214b7b..7f92454 100644 --- a/blueprint/Login.py +++ b/blueprint/Login.py @@ -9,11 +9,15 @@ @Comment : 登录功能的蓝图 """ from flask import Blueprint, render_template - +from blueprint.model import LoginForm # 创建蓝图对象 bp_login = Blueprint('bp_login', __name__) -@bp_login.route('/login') +@bp_login.route('/', methods=['GET', 'POST']) def login(): - return render_template('login.html') + form = LoginForm() + if form.validate_on_submit(): + print(form.account.data) + print(form.password.data) + return render_template('login.html', form=form) diff --git a/blueprint/error.py b/blueprint/error.py new file mode 100644 index 0000000..908bd59 --- /dev/null +++ b/blueprint/error.py @@ -0,0 +1,24 @@ +# -*- coding: UTF-8 -*- +""" +@Project : FlaskProject +@File : error.py +@IDE : PyCharm +@Author : 爱写屎山的王可奕 +@Email : 1933658780@qq.com +@Date : 2023/4/28 9:31 +@Comment : errorhandler的蓝图 +""" +from flask import Blueprint, render_template + +# 创建蓝图对象 +bp_error = Blueprint('bp_error', __name__) + + +@bp_error.app_errorhandler(404) +def page_not_found(e): + return render_template('404.html'), 404 + + +@bp_error.app_errorhandler(500) +def internal_server_error(e): + return render_template('500.html'), 500 diff --git a/blueprint/model.py b/blueprint/model.py new file mode 100644 index 0000000..e822169 --- /dev/null +++ b/blueprint/model.py @@ -0,0 +1,25 @@ +# -*- coding: UTF-8 -*- +""" +@Project : FlaskProject +@File : model.py +@IDE : PyCharm +@Author : 爱写屎山的王可奕 +@Email : 1933658780@qq.com +@Date : 2023/4/28 10:01 +@Comment : 存放各种类 +""" +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, PasswordField +from wtforms.validators import DataRequired +from werkzeug.security import generate_password_hash, check_password_hash + + +class LoginForm(FlaskForm): + account = StringField(label='account', validators=[DataRequired('用户名不能为空')], + render_kw={'class': "form-control", 'type': "text", + 'id': "account", 'placeholder': "账号", + 'required': ""}) + password = PasswordField(label='password', validators=[DataRequired('密码不能为空')], + render_kw={'class': "form-control", 'type': "password", 'id': "password", + 'placeholder': "密码", 'required': ""}) + submit = SubmitField(label='login', render_kw={'class': "btn btn-primary d-block w-100", 'type': "submit"}) diff --git a/requirements.txt b/requirements.txt index 1ce94a6..2ef2221 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -Flask~=2.2.3 \ No newline at end of file +Flask~=2.2.3 +WTForms~=3.0.1 \ No newline at end of file diff --git a/templates/bootstrap/base.html b/templates/bootstrap/base.html new file mode 100644 index 0000000..474bb3a --- /dev/null +++ b/templates/bootstrap/base.html @@ -0,0 +1,34 @@ +{% block doc -%} + + +{%- block html %} + + {%- block head %} + {% block title %}{{title|default}}{% endblock title %} + + {%- block metas %} + + {%- endblock metas %} + + {%- block styles %} + + + {%- endblock styles %} + {%- endblock head %} + + + {% block body -%} + {% block navbar %} + {%- endblock navbar %} + {% block content -%} + {%- endblock content %} + + {% block scripts %} + + + {%- endblock scripts %} + {%- endblock body %} + +{%- endblock html %} + +{% endblock doc -%} diff --git a/templates/bootstrap/fixes.html b/templates/bootstrap/fixes.html new file mode 100644 index 0000000..3471cf9 --- /dev/null +++ b/templates/bootstrap/fixes.html @@ -0,0 +1,6 @@ +{% macro ie8() %} + +{% endmacro %} diff --git a/templates/bootstrap/google.html b/templates/bootstrap/google.html new file mode 100644 index 0000000..356ea63 --- /dev/null +++ b/templates/bootstrap/google.html @@ -0,0 +1,38 @@ +{% macro analytics(account) -%} + +{% endmacro %} + +{% macro uanalytics(id, options='auto', domain=None) %} +{# The uanalytics macro currently contains a hack to support legacy code. + The old signature was ``uanalytics(id, domain)`` when domain was a required + parameter that was passed on to the ga() function. + + To preserve old behavior, if options is not a dictionary, it is passed on + unchanged. The ``domain`` parameter is added to not break calls with named + parameters, it will override any other value for options. + + More modern code can simply pass any desired option to the analytics + function as desired. +#} +{%- if domain != None %} +{%- set options = domain %} +{%- endif %} + +{% endmacro %} diff --git a/templates/bootstrap/pagination.html b/templates/bootstrap/pagination.html new file mode 100644 index 0000000..63c22b3 --- /dev/null +++ b/templates/bootstrap/pagination.html @@ -0,0 +1,51 @@ +{% macro _arg_url_for(endpoint, base) %} +{# calls url_for() with a given endpoint and **base as the parameters, + additionally passing on all keyword_arguments (may overwrite existing ones) + #} +{%- with kargs = base.copy() -%} +{%- do kargs.update(kwargs) -%} +{{url_for(endpoint, **kargs)}} +{%- endwith %} +{%- endmacro %} + +{% macro render_pagination(pagination, + endpoint=None, + prev=('«')|safe, + next=('»')|safe, + size=None, + ellipses='…', + args={} + ) +-%} +{% with url_args = {} %} +{%- do url_args.update(request.view_args if not endpoint else {}), + url_args.update(request.args if not endpoint else {}), + url_args.update(args) -%} +{% with endpoint = endpoint or request.endpoint %} + +{% endwith %} +{% endwith %} +{% endmacro %} diff --git a/templates/bootstrap/utils.html b/templates/bootstrap/utils.html new file mode 100644 index 0000000..e76c7d5 --- /dev/null +++ b/templates/bootstrap/utils.html @@ -0,0 +1,45 @@ +{% macro flashed_messages(messages=None, container=True, transform={ + 'critical': 'danger', + 'error': 'danger', + 'info': 'info', + 'warning': 'warning', + 'debug': 'info', + 'notset': 'info', + 'message': 'info', +}, default_category=None, dismissible=False) -%} +{% with messages = messages or get_flashed_messages(with_categories=True) -%} +{% if messages -%} {# don't output anything if there are no messages #} + +{% if container -%} + +
+
+
+{% endif -%} + +{% for cat, msg in messages %} +{%- endfor -%} + +{% if container %} +
+
+
+ +{% endif -%} + +{% endif -%} +{% endwith -%} +{% endmacro -%} + + +{% macro icon(type=None, extra_classes=[]) -%} + +{%- endmacro %} + + +{% macro form_button(url, content, method='post', class='btn-link') -%} +
+{%- endmacro %} diff --git a/templates/bootstrap/wtf.html b/templates/bootstrap/wtf.html new file mode 100644 index 0000000..0d3ae9c --- /dev/null +++ b/templates/bootstrap/wtf.html @@ -0,0 +1,213 @@ +{% macro form_errors(form, hiddens=True) %} + {%- if form.errors %} + {%- for fieldname, errors in form.errors.items() %} + {%- if bootstrap_is_hidden_field(form[fieldname]) and hiddens or + not bootstrap_is_hidden_field(form[fieldname]) and hiddens != 'only' %} + {%- for error in errors %} +

{{error}}

+ {%- endfor %} + {%- endif %} + {%- endfor %} + {%- endif %} +{%- endmacro %} + +{% macro _hz_form_wrap(horizontal_columns, form_type, add_group=False, required=False) %} +{% if form_type == "horizontal" %} + {% if add_group %}
{% endif %} +
+{% endif %} +{{caller()}} + +{% if form_type == "horizontal" %} + {% if add_group %}
{% endif %} +
+{% endif %} +{% endmacro %} + +{% macro form_field(field, + form_type="basic", + horizontal_columns=('lg', 2, 10), + button_map={}) %} + +{# this is a workaround hack for the more straightforward-code of just passing required=required parameter. older versions of wtforms do not have +the necessary fix for required=False attributes, but will also not set the required flag in the first place. we skirt the issue using the code below #} +{% if field.flags.required and not required in kwargs %} +{% set kwargs = dict(required=True, **kwargs) %} +{% endif %} + +{% if field.widget.input_type == 'checkbox' %} + {% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %} +
+ +
+ {% endcall %} +{%- elif field.type == 'RadioField' -%} + {# note: A cleaner solution would be rendering depending on the widget, + this is just a hack for now, until I can think of something better #} + {% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %} + {% for item in field -%} +
+ +
+ {% endfor %} + {% endcall %} +{%- elif field.type == 'SubmitField' -%} + {# deal with jinja scoping issues? #} + {% set field_kwargs = kwargs %} + + {# note: same issue as above - should check widget, not field type #} + {% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %} + {{field(class='btn btn-%s' % button_map.get(field.name, 'default'), + **field_kwargs)}} + {% endcall %} +{%- elif field.type == 'FormField' -%} +{# note: FormFields are tricky to get right and complex setups requiring + these are probably beyond the scope of what this macro tries to do. + the code below ensures that things don't break horribly if we run into + one, but does not try too hard to get things pretty. #} +
+ {{field.label}} + {%- for subfield in field %} + {% if not bootstrap_is_hidden_field(subfield) -%} + {{ form_field(subfield, + form_type=form_type, + horizontal_columns=horizontal_columns, + button_map=button_map) }} + {%- endif %} + {%- endfor %} +
+{% else -%} +
+ {%- if form_type == "inline" %} + {{field.label(class="sr-only")|safe}} + {% if field.type == 'FileField' %} + {{field(**kwargs)|safe}} + {% else %} + {{field(class="form-control", **kwargs)|safe}} + {% endif %} + {% elif form_type == "horizontal" %} + {{field.label(class="control-label " + ( + " col-%s-%s" % horizontal_columns[0:2] + ))|safe}} +
+ {% if field.type == 'FileField' %} + {{field(**kwargs)|safe}} + {% else %} + {{field(class="form-control", **kwargs)|safe}} + {% endif %} +
+ {%- if field.errors %} + {%- for error in field.errors %} + {% call _hz_form_wrap(horizontal_columns, form_type, required=required) %} +

{{error}}

+ {% endcall %} + {%- endfor %} + {%- elif field.description -%} + {% call _hz_form_wrap(horizontal_columns, form_type, required=required) %} +

{{field.description|safe}}

+ {% endcall %} + {%- endif %} + {%- else -%} + {{field.label(class="control-label")|safe}} + {% if field.type == 'FileField' %} + {{field(**kwargs)|safe}} + {% else %} + {{field(class="form-control", **kwargs)|safe}} + {% endif %} + + {%- if field.errors %} + {%- for error in field.errors %} +

{{error}}

+ {%- endfor %} + {%- elif field.description -%} +

{{field.description|safe}}

+ {%- endif %} + {%- endif %} +
+{% endif %} +{% endmacro %} + +{# valid form types are "basic", "inline" and "horizontal" #} +{% macro quick_form(form, + action="", + method="post", + extra_classes=None, + role="form", + form_type="basic", + horizontal_columns=('lg', 2, 10), + enctype=None, + button_map={}, + id="", + novalidate=False) %} +{#- +action="" is what we want, from http://www.ietf.org/rfc/rfc2396.txt: + +4.2. Same-document References + + A URI reference that does not contain a URI is a reference to the + current document. In other words, an empty URI reference within a + document is interpreted as a reference to the start of that document, + and a reference containing only a fragment identifier is a reference + to the identified fragment of that document. Traversal of such a + reference should not result in an additional retrieval action. + However, if the URI reference occurs in a context that is always + intended to result in a new request, as in the case of HTML's FORM + element, then an empty URI reference represents the base URI of the + current document and should be replaced by that URI when transformed + into a request. + + -#} +{#- if any file fields are inside the form and enctype is automatic, adjust + if file fields are found. could really use the equalto test of jinja2 + here, but latter is not available until 2.8 + + warning: the code below is guaranteed to make you cry =( +#} +{%- set _enctype = [] %} +{%- if enctype is none -%} + {%- for field in form %} + {%- if field.type == 'FileField' %} + {#- for loops come with a fairly watertight scope, so this list-hack is + used to be able to set values outside of it #} + {%- set _ = _enctype.append('multipart/form-data') -%} + {%- endif %} + {%- endfor %} +{%- else %} + {% set _ = _enctype.append(enctype) %} +{%- endif %} +
+ {{ form.hidden_tag() }} + {{ form_errors(form, hiddens='only') }} + + {%- for field in form %} + {% if not bootstrap_is_hidden_field(field) -%} + {{ form_field(field, + form_type=form_type, + horizontal_columns=horizontal_columns, + button_map=button_map) }} + {%- endif %} + {%- endfor %} + +
+{%- endmacro %} diff --git a/templates/login.html b/templates/login.html index 8c8b652..30b08b7 100644 --- a/templates/login.html +++ b/templates/login.html @@ -18,22 +18,51 @@

请输入您的账号密码

-
+
-
+
+ -
-
+ +
+ {# #} + {# {{ form.hidden_tag() }}#} + {# {{ form.name.label }} {{ form.name() }}#} + {# {{ form.submit() }}#} + {# #} + + +
+ {{ form.hidden_tag() }} + {{ form.account }}
-
-
+
{{ form.password }}
+
{{ form.submit }}
+{# #} +{#
#} +{#
#} +{#
#} +{# #} +{#
#} +{#
#} +{#
注册账号
#} +{# #} +{#
#}