Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use FLASK_ADMIN_ prefix for all app.config configuration #2472

Merged
merged 5 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions doc/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,20 +273,39 @@ Some of the Geometry field types that are available include:
Have a look at https://github.com/flask-admin/flask-admin/tree/master/examples/geo_alchemy
to get started.

Loading Tiles From Mapbox
*************************
Display map widgets
*******************

Flask-Admin uses `Leaflet <https://leafletjs.com/>`_ to display map widgets for
geographical data. By default, this uses `MapBox <https://www.mapbox.com>`_.

To have map data display correctly, you'll have to sign up for an account at https://www.mapbox.com/
and include some credentials in your application's config::
To have MapBox data display correctly, you'll have to sign up for an account and include
some credentials in your application's config::

app = Flask(__name__)
app.config['MAPBOX_MAP_ID'] = "example.abc123"
app.config['MAPBOX_ACCESS_TOKEN'] = "pk.def456"
app.config['FLASK_ADMIN_MAPS'] = True

# Required: configure the default centre position for blank maps
app.config['FLASK_ADMIN_DEFAULT_CENTER_LAT'] = -33.918861
app.config['FLASK_ADMIN_DEFAULT_CENTER_LONG'] = 18.423300

# Required if using the default Mapbox integration
app.config['FLASK_ADMIN_MAPBOX_MAP_ID'] = "example.abc123"
app.config['FLASK_ADMIN_MAPBOX_ACCESS_TOKEN'] = "pk.def456"

If you want to use a map provider other than MapBox (eg OpenStreetMaps), you can override
the tile layer URLs and tile attribution attributes::

class CityView(ModelView):
tile_layer_url = '{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
tile_layer_attribution = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'

Leaflet supports loading map tiles from any arbitrary map tile provider, but
at the moment, Flask-Admin only supports Mapbox. If you want to use other
providers, make a pull request!
If you want to include a search box on map widgets for looking up locations, you need the following additional configuration::

app.config['FLASK_ADMIN_MAPS_SEARCH'] = True
app.config['FLASK_ADMIN_GOOGLE_MAPS_API_KEY'] = 'secret'

Flask-Admin currently only supports Google Maps for map search.

Limitations
***********
Expand Down Expand Up @@ -605,3 +624,34 @@ While the wrapped function should accept only one parameter - `ids`::
raise

flash(gettext('Failed to approve users. %(error)s', error=str(ex)), 'error')


Raise exceptions instead of flash error messages
------------------------------------------------

****

By default, Flask-Admin will capture most exceptions related to reading/writing models
and display a flash message instead of raising an exception. If your Flask app is running
in debug mode (ie under local development), exceptions will not be suppressed.

The flash message behaviour can be overridden with some Flask configuration.::

app = Flask(__name__)
app.config['FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION'] = True
app.config['FLASK_ADMIN_RAISE_ON_INTEGRITY_ERROR'] = True


FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION
***********************************
Instead of turning exceptions on model create/update/delete actions into flash messages,
raise the exception as normal. You should expect the view to return a 500 to the user,
unless you add specific handling to prevent this.

FLASK_ADMIN_RAISE_ON_INTEGRITY_ERROR
************************************
This targets SQLAlchemy specifically.

Unlike the previous setting, this will specifically only affect the behaviour of
IntegrityErrors. These usually come from violations on constraints in the database,
for example trying to insert a row with a primary key that already exists.
8 changes: 6 additions & 2 deletions examples/geo_alchemy/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ To run this example:

python examples/geo_alchemy/app.py

6. You will notice that the maps are not rendered. To see them, you will have
6. You will notice that the maps are not rendered. By default, Flask-Admin expects
an integration with `Mapbox <https://www.mapbox.com/>`_. To see them, you will have
to register for a free account at `Mapbox <https://www.mapbox.com/>`_ and set
the *MAPBOX_MAP_ID* and *MAPBOX_ACCESS_TOKEN* config variables accordingly.
the *FLASK_ADMIN_MAPBOX_MAP_ID* and *FLASK_ADMIN_MAPBOX_ACCESS_TOKEN* config
variables accordingly.

However, some of the maps are overridden to use Open Street Maps
19 changes: 12 additions & 7 deletions examples/geo_alchemy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,21 @@ def index():
admin = admin.Admin(app, name='Example: GeoAlchemy', theme=Bootstrap4Theme())


class ModalModelView(ModelView):
class LeafletModelView(ModelView):
edit_modal = True


class OSMModelView(ModelView):
tile_layer_url = '{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
tile_layer_attribution = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'

# Add views
admin.add_view(ModalModelView(Point, db.session, category='Points'))
admin.add_view(ModalModelView(MultiPoint, db.session, category='Points'))
admin.add_view(ModalModelView(Polygon, db.session, category='Polygons'))
admin.add_view(ModalModelView(MultiPolygon, db.session, category='Polygons'))
admin.add_view(ModalModelView(LineString, db.session, category='Lines'))
admin.add_view(ModalModelView(MultiLineString, db.session, category='Lines'))
admin.add_view(LeafletModelView(Point, db.session, category='Points'))
admin.add_view(OSMModelView(MultiPoint, db.session, category='Points'))
admin.add_view(LeafletModelView(Polygon, db.session, category='Polygons'))
admin.add_view(OSMModelView(MultiPolygon, db.session, category='Polygons'))
admin.add_view(LeafletModelView(LineString, db.session, category='Lines'))
admin.add_view(OSMModelView(MultiLineString, db.session, category='Lines'))

if __name__ == '__main__':

Expand Down
12 changes: 8 additions & 4 deletions examples/geo_alchemy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
SQLALCHEMY_ECHO = True

# credentials for loading map tiles from mapbox
MAPBOX_MAP_ID = 'light-v10' # example map id
MAPBOX_ACCESS_TOKEN = '...'
FLASK_ADMIN_MAPS = True
FLASK_ADMIN_MAPS_SEARCH = False
FLASK_ADMIN_MAPBOX_MAP_ID = 'light-v10' # example map id
FLASK_ADMIN_MAPBOX_ACCESS_TOKEN = '...'

# when the creating new shapes, use this default map center
DEFAULT_CENTER_LAT = -33.918861
DEFAULT_CENTER_LONG = 18.423300
FLASK_ADMIN_DEFAULT_CENTER_LAT = -33.918861
FLASK_ADMIN_DEFAULT_CENTER_LONG = 18.423300

FLASK_ADMIN_GOOGLE_MAPS_API_KEY = '...'
4 changes: 2 additions & 2 deletions flask_admin/contrib/sqla/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,8 +1126,8 @@ def get_one(self, id):
def handle_view_exception(self, exc):
if isinstance(exc, IntegrityError):
if current_app.config.get(
'ADMIN_RAISE_ON_INTEGRITY_ERROR',
current_app.config.get('ADMIN_RAISE_ON_VIEW_EXCEPTION')
'FLASK_ADMIN_RAISE_ON_INTEGRITY_ERROR',
current_app.config.get('FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION')
):
raise
else:
Expand Down
2 changes: 1 addition & 1 deletion flask_admin/model/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,7 @@ def handle_view_exception(self, exc):
flash(as_unicode(exc), 'error')
return True

if current_app.config.get('ADMIN_RAISE_ON_VIEW_EXCEPTION'):
if current_app.config.get('FLASK_ADMIN_RAISE_ON_VIEW_EXCEPTION'):
raise

if self._debug:
Expand Down
16 changes: 8 additions & 8 deletions flask_admin/static/admin/js/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@
* Process Leaflet (map) widget
*/
function processLeafletWidget($el, name) {
if (!window.MAPBOX_MAP_ID) {
console.error("You must set MAPBOX_MAP_ID in your Flask settings to use the map widget");
if (!window.FLASK_ADMIN_MAPS) {
console.error("You must set FLASK_ADMIN_MAPS in your Flask settings to use the map widget");
return false;
}
if (!window.DEFAULT_CENTER_LAT || !window.DEFAULT_CENTER_LONG) {
console.error("You must set DEFAULT_CENTER_LAT and DEFAULT_CENTER_LONG in your Flask settings to use the map widget");
if (!window.FLASK_ADMIN_DEFAULT_CENTER_LAT || !window.FLASK_ADMIN_DEFAULT_CENTER_LONG) {
console.error("You must set FLASK_ADMIN_DEFAULT_CENTER_LAT and FLASK_ADMIN_DEFAULT_CENTER_LONG in your Flask settings to use the map widget");
return false;
}

Expand Down Expand Up @@ -154,19 +154,19 @@
}
} else {
// use the default map center
map.setView([window.DEFAULT_CENTER_LAT, window.DEFAULT_CENTER_LONG], 12);
map.setView([window.FLASK_ADMIN_DEFAULT_CENTER_LAT, window.FLASK_ADMIN_DEFAULT_CENTER_LONG], 12);
}

// set up tiles
var mapboxHostnameAndPath = $el.data('tile-layer-url') || 'api.mapbox.com/styles/v1/mapbox/'+window.MAPBOX_MAP_ID+'/tiles/{z}/{x}/{y}?access_token={accessToken}';
var mapboxHostnameAndPath = $el.data('tile-layer-url') || 'api.mapbox.com/styles/v1/mapbox/'+window.FLASK_ADMIN_MAPBOX_MAP_ID+'/tiles/{z}/{x}/{y}?access_token={accessToken}';
var attribution = $el.data('tile-layer-attribution') || 'Map data &copy; <a href="//openstreetmap.org">OpenStreetMap</a> contributors, <a href="//creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="//mapbox.com">Mapbox</a>';
L.tileLayer('//' + mapboxHostnameAndPath, {
// Attributes from https://docs.mapbox.com/help/troubleshooting/migrate-legacy-static-tiles-api/
attribution: attribution,
maxZoom: 18,
tileSize: 512,
zoomOffset: -1,
accessToken: window.MAPBOX_ACCESS_TOKEN
accessToken: window.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN
}).addTo(map);

// everything below here is to set up editing, so if we're not editable,
Expand Down Expand Up @@ -201,7 +201,7 @@
}
var drawControl = new L.Control.Draw(drawOptions);
map.addControl(drawControl);
if (window.MAPBOX_SEARCH) {
if (window.FLASK_ADMIN_MAPS_SEARCH) {
var circle = L.circleMarker([0, 0]);
var $autocompleteEl = $('<input style="position: absolute; z-index: 9999; display: block; margin: -42px 0 0 10px; width: 50%">');
var $form = $($el.get(0).form);
Expand Down
23 changes: 12 additions & 11 deletions flask_admin/templates/bootstrap2/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ <h3>{{ text }}</h3>
{% macro form_css() %}
<link href="{{ admin_static.url(filename='vendor/select2/select2.css', v='3.5.2') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker-bs2.css', v='1.3.22') }}" rel="stylesheet">
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.css', v='1.0.2') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.css', v='0.4.6') }}" rel="stylesheet">
{% endif %}
Expand All @@ -228,24 +228,25 @@ <h3>{{ text }}</h3>
{% endmacro %}

{% macro form_js() %}
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<script>
window.MAPBOX_MAP_ID = "{{ config.MAPBOX_MAP_ID }}";
{% if config.MAPBOX_ACCESS_TOKEN %}
window.MAPBOX_ACCESS_TOKEN = "{{ config.MAPBOX_ACCESS_TOKEN }}";
window.FLASK_ADMIN_MAPS = true;
window.FLASK_ADMIN_MAPBOX_MAP_ID = "{{ config.FLASK_ADMIN_MAPBOX_MAP_ID }}";
{% if config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN %}
window.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN = "{{ config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN }}";
{% endif %}
{% if config.DEFAULT_CENTER_LAT and config.DEFAULT_CENTER_LONG %}
window.DEFAULT_CENTER_LAT = "{{ config.DEFAULT_CENTER_LAT }}";
window.DEFAULT_CENTER_LONG = "{{ config.DEFAULT_CENTER_LONG }}";
{% if config.FLASK_ADMIN_DEFAULT_CENTER_LAT and config.FLASK_ADMIN_DEFAULT_CENTER_LONG %}
window.FLASK_ADMIN_DEFAULT_CENTER_LAT = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LAT }}";
window.FLASK_ADMIN_DEFAULT_CENTER_LONG = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LONG }}";
{% endif %}
</script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.js', v='1.0.2') }}"></script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.js', v='0.4.6') }}"></script>
{% if config.MAPBOX_SEARCH %}
{% if config.FLASK_ADMIN_MAPS_SEARCH %}
<script>
window.MAPBOX_SEARCH = "{{ config.MAPBOX_SEARCH }}";
window.FLASK_ADMIN_MAPS_SEARCH = "{{ config.FLASK_ADMIN_MAPS_SEARCH }}";
</script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('GOOGLE_MAPS_API_KEY') }}"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('FLASK_ADMIN_GOOGLE_MAPS_API_KEY') }}"></script>
{% endif %}
{% endif %}
<script src="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js', v='1.3.22') }}"></script>
Expand Down
23 changes: 12 additions & 11 deletions flask_admin/templates/bootstrap3/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ <h3>{{ text }}</h3>
<link href="{{ admin_static.url(filename='vendor/select2/select2.css', v='3.5.2') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/select2/select2-bootstrap3.css', v='1.4.6') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker-bs3.css', v='1.3.22') }}" rel="stylesheet">
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.css', v='1.0.2') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.css', v='0.4.6') }}" rel="stylesheet">
{% endif %}
Expand All @@ -219,24 +219,25 @@ <h3>{{ text }}</h3>
{% endmacro %}

{% macro form_js() %}
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<script>
window.MAPBOX_MAP_ID = "{{ config.MAPBOX_MAP_ID }}";
{% if config.MAPBOX_ACCESS_TOKEN %}
window.MAPBOX_ACCESS_TOKEN = "{{ config.MAPBOX_ACCESS_TOKEN }}";
window.FLASK_ADMIN_MAPS = true;
window.FLASK_ADMIN_MAPBOX_MAP_ID = "{{ config.FLASK_ADMIN_MAPBOX_MAP_ID }}";
{% if config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN %}
window.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN = "{{ config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN }}";
{% endif %}
{% if config.DEFAULT_CENTER_LAT and config.DEFAULT_CENTER_LONG %}
window.DEFAULT_CENTER_LAT = "{{ config.DEFAULT_CENTER_LAT }}";
window.DEFAULT_CENTER_LONG = "{{ config.DEFAULT_CENTER_LONG }}";
{% if config.FLASK_ADMIN_DEFAULT_CENTER_LAT and config.FLASK_ADMIN_DEFAULT_CENTER_LONG %}
window.FLASK_ADMIN_DEFAULT_CENTER_LAT = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LAT }}";
window.FLASK_ADMIN_DEFAULT_CENTER_LONG = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LONG }}";
{% endif %}
</script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.js', v='1.0.2') }}"></script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.js', v='0.4.6') }}"></script>
{% if config.MAPBOX_SEARCH %}
{% if config.FLASK_ADMIN_MAPS_SEARCH %}
<script>
window.MAPBOX_SEARCH = "{{ config.MAPBOX_SEARCH }}";
window.FLASK_ADMIN_MAPS_SEARCH = "{{ config.FLASK_ADMIN_MAPS_SEARCH }}";
</script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('GOOGLE_MAPS_API_KEY') }}"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('FLASK_ADMIN_GOOGLE_MAPS_API_KEY') }}"></script>
{% endif %}
{% endif %}
<script src="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js', v='1.3.22') }}"></script>
Expand Down
23 changes: 12 additions & 11 deletions flask_admin/templates/bootstrap4/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ <h3>{{ text }}</h3>
<link href="{{ admin_static.url(filename='vendor/select2/select2.css', v='4.2.1') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/select2/select2-bootstrap4.css', v='1.4.6') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker-bs4.css', v='1.3.22') }}" rel="stylesheet">
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.css', v='1.0.2') }}" rel="stylesheet">
<link href="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.css', v='0.4.6') }}" rel="stylesheet">
{% endif %}
Expand All @@ -257,24 +257,25 @@ <h3>{{ text }}</h3>
{% endmacro %}

{% macro form_js() %}
{% if config.MAPBOX_MAP_ID %}
{% if config.FLASK_ADMIN_MAPS %}
<script>
window.MAPBOX_MAP_ID = "{{ config.MAPBOX_MAP_ID }}";
{% if config.MAPBOX_ACCESS_TOKEN %}
window.MAPBOX_ACCESS_TOKEN = "{{ config.MAPBOX_ACCESS_TOKEN }}";
window.FLASK_ADMIN_MAPS = true;
window.FLASK_ADMIN_MAPBOX_MAP_ID = "{{ config.FLASK_ADMIN_MAPBOX_MAP_ID }}";
{% if config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN %}
window.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN = "{{ config.FLASK_ADMIN_MAPBOX_ACCESS_TOKEN }}";
{% endif %}
{% if config.DEFAULT_CENTER_LAT and config.DEFAULT_CENTER_LONG %}
window.DEFAULT_CENTER_LAT = "{{ config.DEFAULT_CENTER_LAT }}";
window.DEFAULT_CENTER_LONG = "{{ config.DEFAULT_CENTER_LONG }}";
{% if config.FLASK_ADMIN_DEFAULT_CENTER_LAT and config.FLASK_ADMIN_DEFAULT_CENTER_LONG %}
window.FLASK_ADMIN_DEFAULT_CENTER_LAT = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LAT }}";
window.FLASK_ADMIN_DEFAULT_CENTER_LONG = "{{ config.FLASK_ADMIN_DEFAULT_CENTER_LONG }}";
{% endif %}
</script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.js', v='1.0.2') }}"></script>
<script src="{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.js', v='0.4.6') }}"></script>
{% if config.MAPBOX_SEARCH %}
{% if config.FLASK_ADMIN_MAPS_SEARCH %}
<script>
window.MAPBOX_SEARCH = "{{ config.MAPBOX_SEARCH }}";
window.FLASK_ADMIN_MAPS_SEARCH = "{{ config.FLASK_ADMIN_MAPS_SEARCH }}";
</script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('GOOGLE_MAPS_API_KEY') }}"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&key={{ config.get('FLASK_ADMIN_GOOGLE_MAPS_API_KEY') }}"></script>
{% endif %}
{% endif %}
<script src="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js', v='1.3.22') }}"></script>
Expand Down
Loading