Skip to content

Commit 2ed7e68

Browse files
Merge remote-tracking branch 'chapter-11/vol-3' into vol-3
2 parents e026122 + 22477c0 commit 2ed7e68

12 files changed

+372
-131
lines changed

Diff for: generate_profile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from werkzeug.contrib.profiler import ProfilerMiddleware
1+
from werkzeug.middleware.profiler import ProfilerMiddleware
22
from my_app import app
33

44
app.wsgi_app = ProfilerMiddleware(app.wsgi_app, restrictions = [10])

Diff for: my_app/__init__.py

+56-34
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
newrelic.agent.initialize('newrelic.ini')
33

44
import os
5-
from flask import Flask
5+
from flask import Flask, g
66
from flask_sqlalchemy import SQLAlchemy
77
from flask_babel import Babel
88
import sentry_sdk
@@ -23,43 +23,65 @@
2323
integrations=[FlaskIntegration()]
2424
)
2525

26-
app = Flask(__name__)
27-
app.config['UPLOAD_FOLDER'] = '/Users/shalabhaggarwal/workspace/mydev/flask_test_uploads'
28-
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
29-
app.config['WTF_CSRF_SECRET_KEY'] = 'random key for form'
30-
app.config['AWS_ACCESS_KEY'] = 'Amazon Access Key'
31-
app.config['AWS_SECRET_KEY'] = 'Amazon Secret Key'
32-
app.config['AWS_BUCKET'] = 'flask-cookbook'
33-
db = SQLAlchemy(app)
34-
35-
app.config['LOG_FILE'] = '/tmp/application.log'
36-
37-
38-
if not app.debug:
39-
import logging
40-
logging.basicConfig(level=logging.INFO)
41-
from logging import FileHandler, Formatter
42-
from logging.handlers import SMTPHandler
43-
file_handler = FileHandler(app.config['LOG_FILE'])
44-
app.logger.addHandler(file_handler)
45-
mail_handler = SMTPHandler(
46-
("smtp.gmail.com", 587), '[email protected]', RECEPIENTS,
47-
'Error occurred in your application',
48-
('[email protected]', 'some_gmail_password'), secure=())
49-
mail_handler.setLevel(logging.ERROR)
50-
# app.logger.addHandler(mail_handler)
51-
for handler in [file_handler, mail_handler]:
52-
handler.setFormatter(Formatter(
53-
'%(asctime)s %(levelname)s: %(message)s '
54-
'[in %(pathname)s:%(lineno)d]'
55-
))
26+
db = SQLAlchemy()
5627

28+
def create_app(alt_config={}):
29+
app = Flask(
30+
__name__,
31+
template_folder=alt_config.get('TEMPLATE_FOLDER', 'templates')
32+
)
5733

58-
babel = Babel(app)
34+
app.config['UPLOAD_FOLDER'] = os.path.realpath('.') + '/my_app/static/uploads'
35+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
36+
app.config['WTF_CSRF_SECRET_KEY'] = 'random key for form'
37+
app.config['LOG_FILE'] = 'application.log'
38+
app.config['AWS_ACCESS_KEY'] = 'Amazon Access Key'
39+
app.config['AWS_SECRET_KEY'] = 'Amazon Secret Key'
40+
app.config['AWS_BUCKET'] = 'flask-cookbook'
41+
app.config['LOG_FILE'] = '/tmp/application.log'
42+
43+
app.config.update(alt_config)
44+
45+
if not app.debug:
46+
import logging
47+
from logging import FileHandler, Formatter
48+
from logging.handlers import SMTPHandler
49+
file_handler = FileHandler(app.config['LOG_FILE'])
50+
app.logger.setLevel(logging.INFO)
51+
app.logger.addHandler(file_handler)
52+
mail_handler = SMTPHandler(
53+
("smtp.gmail.com", 587), '[email protected]', RECEPIENTS,
54+
'Error occurred in your application',
55+
('[email protected]', 'some_gmail_password'), secure=())
56+
mail_handler.setLevel(logging.ERROR)
57+
# app.logger.addHandler(mail_handler)
58+
for handler in [file_handler, mail_handler]:
59+
handler.setFormatter(Formatter(
60+
'%(asctime)s %(levelname)s: %(message)s '
61+
'[in %(pathname)s:%(lineno)d]'
62+
))
63+
64+
app.secret_key = 'some_random_key'
65+
66+
return app
67+
68+
def create_db(app):
69+
db.init_app(app)
70+
with app.app_context():
71+
db.create_all()
5972

60-
app.secret_key = 'some_random_key'
73+
return db
74+
75+
76+
def get_locale():
77+
return g.get('current_lang', 'en')
78+
79+
80+
app = create_app()
81+
babel = Babel(app)
82+
babel.init_app(app, locale_selector=get_locale)
6183

6284
from my_app.catalog.views import catalog
6385
app.register_blueprint(catalog)
6486

65-
db.create_all()
87+
db = create_db(app)

Diff for: my_app/catalog/models.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from decimal import Decimal
22
from flask_wtf import FlaskForm
33
from flask_wtf.file import FileField, FileRequired
4-
from wtforms import TextField, DecimalField, SelectField
4+
from wtforms import StringField, DecimalField, SelectField
55
from wtforms.validators import InputRequired, NumberRange, ValidationError
6-
from wtforms.widgets import html_params, Select, HTMLString
6+
from wtforms.widgets import html_params, Select
7+
from markupsafe import Markup
78
from flask_wtf import Form
89
from flask_babel import lazy_gettext as _
910
from my_app import db
@@ -43,7 +44,7 @@ def __repr__(self):
4344

4445

4546
class NameForm(FlaskForm):
46-
name = TextField(_('Name'), validators=[InputRequired()])
47+
name = StringField(_('Name'), validators=[InputRequired()])
4748

4849

4950
class CustomCategoryInput(Select):
@@ -59,7 +60,7 @@ def __call__(self, field, **kwargs):
5960
), label
6061
)
6162
)
62-
return HTMLString(' '.join(html))
63+
return Markup(' '.join(html))
6364

6465

6566
class CategoryField(SelectField):
@@ -106,6 +107,6 @@ def _check_duplicate(form, field):
106107

107108

108109
class CategoryForm(NameForm):
109-
name = TextField(_('Name'), validators=[
110+
name = StringField(_('Name'), validators=[
110111
InputRequired(), check_duplicate_category()
111112
])

Diff for: my_app/catalog/views.py

+19-24
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import os
22
from functools import wraps
3-
from werkzeug import secure_filename
3+
from werkzeug.utils import secure_filename
44
from flask import request, Blueprint, render_template, jsonify, flash, \
5-
redirect, url_for as flask_url_for, g, abort
6-
from my_app import db, app, ALLOWED_EXTENSIONS, babel
5+
redirect, url_for as flask_url_for, g, abort, current_app
6+
from my_app import db, ALLOWED_EXTENSIONS, babel
77
from my_app.catalog.models import Product, Category, ProductForm, CategoryForm
8-
from sqlalchemy.orm.util import join
8+
from sqlalchemy.orm import join
99
from flask_babel import lazy_gettext as _
1010
import geoip2.database
1111
from geoip2.errors import AddressNotFoundError
@@ -14,14 +14,14 @@
1414
catalog = Blueprint('catalog', __name__)
1515

1616

17-
@app.before_request
17+
@catalog.before_request
1818
def before():
1919
if request.view_args and 'lang' in request.view_args:
2020
g.current_lang = request.view_args['lang']
2121
request.view_args.pop('lang')
2222

2323

24-
@app.context_processor
24+
@catalog.context_processor
2525
def inject_url_for():
2626
return {
2727
'url_for': lambda endpoint, **kwargs: flask_url_for(
@@ -33,11 +33,6 @@ def inject_url_for():
3333
url_for = inject_url_for()['url_for']
3434

3535

36-
@babel.localeselector
37-
def get_locale():
38-
return g.get('current_lang', 'en')
39-
40-
4136
def template_or_json(template=None):
4237
""""Return a dict from your view and this will either
4338
pass it to a template or render json. Use like:
@@ -48,7 +43,7 @@ def decorated(f):
4843
@wraps(f)
4944
def decorated_fn(*args, **kwargs):
5045
ctx = f(*args, **kwargs)
51-
if request.is_xhr or not template:
46+
if request.headers.get("X-Requested-With") == "XMLHttpRequest" or not template:
5247
return jsonify(ctx)
5348
else:
5449
return render_template(template, **ctx)
@@ -61,9 +56,9 @@ def allowed_file(filename):
6156
filename.lower().rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
6257

6358

64-
@app.errorhandler(404)
59+
@catalog.errorhandler(404)
6560
def page_not_found(e):
66-
app.logger.error(e)
61+
current_app.logger.error(e)
6762
return render_template('404.html'), 404
6863

6964

@@ -73,7 +68,7 @@ def page_not_found(e):
7368
@template_or_json('home.html')
7469
def home():
7570
products = Product.query.all()
76-
app.logger.info(
71+
current_app.logger.info(
7772
'Home page with total of %d products' % len(products)
7873
)
7974
return {'count': len(products)}
@@ -83,15 +78,15 @@ def home():
8378
def product(id):
8479
product = Product.query.filter_by(id=id).first()
8580
if not product:
86-
app.logger.warning('Requested product not found.')
81+
current_app.logger.warning('Requested product not found.')
8782
abort(404)
8883
return render_template('product.html', product=product)
8984

9085

9186
@catalog.route('/<lang>/products')
9287
@catalog.route('/<lang>/products/<int:page>')
9388
def products(page=1):
94-
products = Product.query.paginate(page, 10)
89+
products = Product.query.paginate(page=page, per_page=10)
9590
return render_template('products.html', products=products)
9691

9792

@@ -110,25 +105,25 @@ def create_product():
110105
if image and allowed_file(image.filename):
111106
filename = secure_filename(image.filename)
112107
session = boto3.Session(
113-
aws_access_key_id=app.config['AWS_ACCESS_KEY'],
114-
aws_secret_access_key=app.config['AWS_SECRET_KEY']
108+
aws_access_key_id=current_app.config['AWS_ACCESS_KEY'],
109+
aws_secret_access_key=current_app.config['AWS_SECRET_KEY']
115110
)
116111
s3 = session.resource('s3')
117-
bucket = s3.Bucket(app.config['AWS_BUCKET'])
112+
bucket = s3.Bucket(current_app.config['AWS_BUCKET'])
118113
if bucket not in list(s3.buckets.all()):
119114
bucket = s3.create_bucket(
120-
Bucket=app.config['AWS_BUCKET'],
115+
Bucket=current_app.config['AWS_BUCKET'],
121116
CreateBucketConfiguration={
122117
'LocationConstraint': 'ap-south-1'
123118
},
124119
)
125120
bucket.upload_fileobj(
126121
image, filename,
127122
ExtraArgs={'ACL': 'public-read'})
128-
reader = geoip2.database.Reader('GeoLite2-City_20190416/GeoLite2-City.mmdb')
123+
reader = geoip2.database.Reader('GeoLite2-City_20230113/GeoLite2-City.mmdb')
129124
try:
130125
match = reader.city(request.remote_addr)
131-
except AddressNotFoundError:
126+
except geoip2.errors.AddressNotFoundError:
132127
match = None
133128

134129
product = Product(
@@ -168,7 +163,7 @@ def product_search(page=1):
168163
Category.name.like('%' + category + '%')
169164
)
170165
return render_template(
171-
'products.html', products=products.paginate(page, 10)
166+
'products.html', products=products.paginate(page=page, per_page=10)
172167
)
173168

174169

0 commit comments

Comments
 (0)