Commit 5ad1fd96 authored by Serge S. Koval's avatar Serge S. Koval

Merge branch 'master' of github.com:/mrjoes/flask-admin

parents 8b30967e d6b827f4
......@@ -13,7 +13,6 @@ flask_admin/tests/tmp
dist/*
make.bat
venv
*.sqlite
*.sublime-*
.coverage
__pycache__
......
......@@ -7,9 +7,9 @@ Flask-Admin
Introduction
------------
Flask-Admin is a batteries-included, simple-to-use Flask extension that lets you add admin interfaces to Flask
applications. It is inspired by the *django-admin* package, but implemented in such a way that the developer has total control
of the look, feel and functionality of the resulting application.
Flask-Admin is a batteries-included, simple-to-use `Flask <http://flask.pocoo.org/>`_ extension that lets you
add admin interfaces to Flask applications. It is inspired by the *django-admin* package, but implemented in such
a way that the developer has total control of the look, feel and functionality of the resulting application.
Out-of-the-box, Flask-Admin plays nicely with various ORM's, including
......@@ -23,8 +23,6 @@ Out-of-the-box, Flask-Admin plays nicely with various ORM's, including
It also boasts a simple file management interface and a `redis client <http://redis.io/>`_ console.
Several usage examples are included in the */examples* folder. Feel free to add your own examples, or improve some of the existing ones, and submit them as a *pull-request*.
The biggest feature of Flask-Admin is flexibility. It aims to provide a set of simple tools that can be used for
building admin interfaces of any complexity. So, to start off with you can create a very simple application in no time,
with auto-generated CRUD-views for each of your models. But then you can go further and customize those views & forms
......@@ -32,11 +30,32 @@ as the need arises.
Flask-Admin is an active project, well-tested and production ready.
Examples
--------
Several usage examples are included in the */examples* folder. Please feel free to add your own examples, or improve
on some of the existing ones, and then submit them via GitHub as a *pull-request*.
You can see some of these examples in action at `http://examples.flask-admin.org <http://examples.flask-admin.org/>`_.
To run one of the examples in your local environment, simply::
cd flask-admin
python examples/simple/simple.py
Documentation
-------------
Flask-Admin is extensively documented, you can find all of the documentation at `http://readthedocs.org/docs/flask-admin <http://readthedocs.org/docs/flask-admin>`_.
The docs are auto-generated for the *.rst* files in the */doc* folder. So if you come across any errors, or think of anything that should be included, then please make the changes and submit them as a *pull-request*.
The docs are auto-generated from the *.rst* files in the */doc* folder. So if you come across any errors, or
if you think of anything else that should be included, then please make the changes and submit them as a *pull-request*.
To build the docs in your local environment::
sudo pip install sphinx
cd flask-admin
sudo make html
Or, if you want to preview any *.rst* snippets that you may want to contribute, go to `http://rst.ninjs.org/ <http://rst.ninjs.org/>`_.
Installation
------------
......@@ -63,8 +82,9 @@ and then::
cd flask-admin
nosetests
You should see output such as::
You should see output similar to::
...
----------------------------------------------------------------------
Ran 41 tests in 2.092s
......
......@@ -4,7 +4,7 @@ stylesheet = flasky.css
pygments_style = flask_theme_support.FlaskyStyle
[options]
index_logo =
index_logo_height = 120px
index_logo = 'flask-admin.png'
index_logo_height = 140px
touch_icon =
github_fork = 'mrjoes/flask-admin'
......@@ -4,7 +4,7 @@ Changelog
1.0.7
-----
Full change log and feature walkthrough can be found `here <http://mrjoes.github.io/2013/03/22/flask-admin-107.html>`_.
Full change log and feature walkthrough can be found `here <http://mrjoes.github.io/2013/10/21/flask-admin-107.html>`_.
Highlights:
......
......@@ -115,12 +115,12 @@ html_theme_path = ['_themes']
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
html_logo = '_static/logo.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
......@@ -129,7 +129,7 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
......
Database backends
=================
The purpose of Flask-Admin is to help you manage your data. For this, it needs some database backend in order to be
able to access that data in the first place. At present, there are four different backends for you to choose
from, depending on which database you would like to use for your application.
.. toctree::
:maxdepth: 2
......@@ -8,3 +12,17 @@ Database backends
db_mongoengine
db_peewee
db_pymongo
If you don't know where to start, but you're familiar with relational databases, then you should probably look at using
`SQLAlchemy <http://www.sqlalchemy.org/>`_. It is a full-featured toolkit, with support for SQLite, PostgreSQL, MySQL,
Oracle and MS-SQL amongst others. It really comes into its own once you have lots of data, and a fair amount of
relations between your data models.
If you're looking for something simpler, or your data models are reasonably self-contained, then
`MongoEngine <http://mongoengine.org/>`_ could be a better option. It is a python wrapper around the popular
*NoSQL* database called `MongoDB <http://www.mongodb.org/>`_.
Of course, if you feel that there's an awesome database wrapper that is missing from the list above, we'd greatly
appreciate it if you could write the plugin for it and submit it as a pull request. A special section of these docs
are dedicated to helping you through this process. See :doc:`model_guidelines`.
Migrating from Django
=====================
If you used `Django <https://www.djangoproject.com/>`_ before, you might find Flask-Admin work slightly different than you expect.
If you are used to `Django <https://www.djangoproject.com/>`_ and the *django-admin* package, you will find
Flask-Admin to work slightly different from what you would expect.
This guide will help you to get acquainted with the Flask-Admin library. Some prior Flask knowledge will be required.
This guide will help you to get acquainted with the Flask-Admin library. It is assumed that you have some prior
knowledge of `Flask <http://flask.pocoo.org/>`_ .
Architecture
------------
Design Philosophy
-----------------
Django does lots of things automatically. For example, it is importing models from the `models.py`, administrative interface
declarations from `admin.py` and so on.
In general, Django and *django-admin* strives to make life easier by implementing sensible defaults. So a developer
will be able to get an application up in no time, but it will have to conform to most of the defaults. Of course it
is possible to customize things, but this often requires a good understanding of what's going on behind the scenes,
and it can be rather tricky and time-consuming.
Flask philosophy is slightly different - explicit is better than implicit. If something should be initialized, it should be
initialized by the developer.
The design philosophy behind Flask is slightly different. It embraces the diversity that one tends to find in web
applications by not forcing design decisions onto the developer. Rather than making it very easy to build an
application that *almost* solves your whole problem, and then letting you figure out the last bit, Flask aims to make it
possible for you to build the *whole* application. It might take a little more effort to get started, but once you've
got the hang of it, the sky is the limit... Even when your application is a little different from most other
applications out there on the web.
Flask-Admin follows this convention. It is up for you, as a developer, to tell Flask-Admin what should be displayed and how.
Flask-Admin follows this same design philosophy. So even though it provides you with several tools for getting up &
running quickly, it will be up to you, as a developer, to tell Flask-Admin what should be displayed and how. Even
though it is easy to get started with a simple `CRUD <http://en.wikipedia.org/wiki/Create,_read,_update_and_delete>`_
interface for each model in your application, Flask-Admin doesn't fix you to this approach, and you are free to
define other ways of interacting with some, or all, of your models.
Sometimes this will require writing a bit of boilerplate code, but it will pay off in the future, especially if you
will have to implement some custom logic.
All Flask-Admin functionality is incapsulated into classes with view methods. Class should be instantiated and plugged to the
administrative framework for its views to be accessible by the users. Nothing prevents from creating more than one instance
of the class and plug them using different base URL - it will work as expected.
Another big difference - Flask-Admin is not built around model CRUD interface. CRUD is just extension of the base administrative
framework. In a nutshell, it is just a class which accepts model in its constructor and exposes few views (list, create, edit, etc).
And as Flask-Admin supports more than one ORM (SQLAlchemy, MongoEngine, Peewee, raw pymongo), developer can mix different model
types in one application by instantiating appropriate CRUD classes.
Due to Flask-Admin supporting more than one ORM (SQLAlchemy, MongoEngine, Peewee, raw pymongo), the developer is even
free to mix different model types into one application by instantiating appropriate CRUD classes.
Getting started
---------------
Lets write a bit of code to create CRUD interface for `Post` SQLAlchemy model. This example uses Flask-SQLAlchemy extension,
but you don't have to use it, Flask-Admin will work with SQLAlchemy declarative extension too. To the code::
At the basis of Flask-Admin is the idea that you can add components to your admin interface by declaring a separate
class for each component, and then adding a method to that class for every view that should be associated to the
component. Since classes can inherit from one another, and since several instances of the same class can be created,
this approach allows for a great deal of flexibility.
Let's write a bit of code to create a simple CRUD interface for the `Post` SQLAlchemy model. The example below uses the
Flask-SQLAlchemy extension, but you don't have to use it (you could also use the SQLAlchemy declarative extension)::
from flask import Flask
from flask.ext.admin import Admin
......@@ -50,7 +58,8 @@ but you don't have to use it, Flask-Admin will work with SQLAlchemy declarative
admin = Admin(app)
admin.add_view(ModelView(Post, db.session))
You can customize behavior of CRUD interface by using special properties, like Django does::
To customize the behavior of the model's CRUD interface, you can set values for some of the special
properties (as listed below) that are made available through `model.BaseModelView`, or one of the ORM wrappers::
# ... imports
......@@ -64,7 +73,7 @@ You can customize behavior of CRUD interface by using special properties, like D
admin.add_view(PostView())
But because administrative interface is implemented as class, you can customize it in constructor as well::
Because each component is implemented as a class, you can also customize it in the constructor::
class PostView(ModelView):
list_columns = ('title',)
......@@ -75,7 +84,8 @@ But because administrative interface is implemented as class, you can customize
super(PostView, self).__init__(Post, db.session)
Here is comparison table between some Django configuration properties and Flask-Admin SQLAlchemy backend properties:
Here is a list of some of the configuration properties that are made available by Flask-Admin and the
SQLAlchemy backend. You can also see which *django-admin* properties they correspond to:
=========================================== ==============================================
Django Flask-Admin
......@@ -96,18 +106,19 @@ change_form_template :attr:`~flask.ext.admin.model.BaseModelView.change_for
You might want to check :doc:`api/mod_model` for basic model configuration options (reused by all model
backends) and specific backend documentation, for example :doc:`api/mod_contrib_sqla`. There's much more
than displayed in this table.
than what is displayed in this table.
Authentication
--------------
If you need to restrict access to the administrative interface, you need to override `is_accessible` method. For example::
To restrict access to your admin interface, you can implement your own class for creating admin components, and
override the `is_accessible` method::
class MyModelView(ModelView):
def is_accessible(self):
return login.current_user.is_authenticated()
If administrative piece is not accessible by the user, it won't be displayed in the menu as well.
Components that are not accessible to a particular user, will also not be displayed in the menu for that user.
Templates
---------
......@@ -115,7 +126,7 @@ Templates
Flask-Admin uses Jinja2 templating engine. Jinja2 is pretty advanced templating engine and Flask-Admin templates were made
to be easily extensible.
For example, if you need to include javascript snippet on edit page for your model, it is easy to do::
For example, if you need to include a javascript snippet on the *Edit* page for one of your models, you could::
{% extends 'admin/model/edit.html' %}
......@@ -124,27 +135,27 @@ For example, if you need to include javascript snippet on edit page for your mod
<script language="javascript">alert('Hello World!')</script>
{% endblock %}
And then point your class to this new template::
and then point your class to this new template::
class MyModelView(ModelView):
edit_template = 'my_edit_template.html'
For list of template blocks, check :doc:`templates`.
For list of available template blocks, check :doc:`templates`.
Tips and hints
--------------
1. Programming with Flask-Admin is not very different from normal application development - write some views, expose
them to the user in constistent user interface.
1. Programming with Flask-Admin is not very different from normal application development - write some views and expose
them to the user, using templates to create a consistent user experience.
2. If you're missing some functionality which can be used more than once, you can create your own "base" class and use
it instead of default implementation
2. If you are missing some functionality which can be used more than once, you can create your own "base" class and use
it instead of default implementation.
3. Due to more advanced templating engine, you can easily extend existing templates. You can even change look and feel
of the administrative UI completely, if you want to. Check `this example <https://github.com/mrjoes/flask-admin/tree/master/examples/layout>`_.
3. Using Jinja2, you can easily extend the existing templates. You can even change the look and feel of the admin
interface completely, if you want to. Check `this example <https://github.com/mrjoes/flask-admin/tree/master/examples/layout>`_.
4. You're not limited to CRUD interface. Want to add some kind of realtime monitoring via websockets? No problem at all
4. You are not limited to a simple CRUD interface for every model. Want to add some kind of realtime monitoring via websockets? No problem.
5. There's so called "index view". By default it is empty, but you can put any information you need there. It is displayed
under Home menu option.
5. There's a so called "index view". By default it is empty, but you can put any information you need there. It is displayed
under the *Home* menu option.
Form rendering rules
--------------------
====================
Before version 1.0.7, all model backends were rendering the creation and editing forms
using the special Jinja2 macro, which was looping over WTForms form object fields and displaying
them one by one.
Before version 1.0.7, all model backends were rendering the *create* and *edit* forms
using a special Jinja2 macro, which was looping over the fields of a WTForms form object and displaying
them one by one. This works well, but it is difficult to customize.
Starting from version 1.0.7, Flask-Admin supports so called form rendering rules.
Starting from version 1.0.7, Flask-Admin supports form rendering rules, to give you fine grained control of how
the forms for your modules should be displayed.
Idea is pretty simple: instead of having non-configurable macro that renders the form,
have a set of rules that tell Flask-Admin how form should be rendered. As an extension
of the idea, rules can output HTML, call Jinja2 macros, render fields and so on.
The basic idea is pretty simple: the customizable rendering rules replace a static macro, so that you can tell
Flask-Admin how each form should be rendered. As an extension, however, the rendering rules also let you do a
bit more: You can use them to output HTML, call Jinja2 macros, render fields and so on.
Essentially, form rendering rules abstract form rendering away from the form definition. And it
no longer matters what is sequence of the fields in the form.
Essentially, form rendering rules abstract the rendering, so that it becomes separate from the form definition. So,
for example, it no longer matters in which sequence yur form fields are defined.
Getting started
---------------
To start using form rendering rules, you need to put list of form field names into `form_create_rules`
property of your administrative view::
To start using the form rendering rules, put a list of form field names into the `form_create_rules`
property one of your admin views::
class RuleView(sqla.ModelView):
form_create_rules = ('email', 'first_name', 'last_name')
In this example, only three fields will be rendered and `email` field will be above other two fields.
Whenever Flask-Admin sees string as a value in `form_create_rules`, it automatically assumes that it is
form field reference and created :class:`flask.ext.admin.form.rules.Field` class instance.
Whenever Flask-Admin sees a string value in `form_create_rules`, it automatically assumes that it is a
form field reference and creates a :class:`flask.ext.admin.form.rules.Field` class instance for that field.
Lets say we want to display 'Foobar' text between `email` and `first_name` fields. This can be accomplished by
using :class:`flask.ext.admin.form.rules.Text` class::
Lets say we want to display some text between the `email` and `first_name` fields. This can be accomplished by
using the :class:`flask.ext.admin.form.rules.Text` class::
from flask.ext.admin.form import rules
class RuleView(sqla.ModelView):
form_create_rules = ('email', rules.Text('Foobar'), 'first_name', 'last_name')
Flask-Admin comes with few built-in rules that can be found in :mod:`flask.ext.admin.form.rules` module:
Built-in rules
--------------
Flask-Admin comes with few built-in rules that can be found in the :mod:`flask.ext.admin.form.rules` module:
======================================================= ========================================================
Form Rendering Rule Description
======================================================= ========================================================
:class:`flask.ext.admin.form.rules.BaseRule` All rules derive from this class
:class:`flask.ext.admin.form.rules.NestedRule` Allows rule nesting, useful for HTML containers
......@@ -50,5 +56,8 @@ Flask-Admin comes with few built-in rules that can be found in :mod:`flask.ext.a
:class:`flask.ext.admin.form.rules.FieldSet` Renders form header and child rules
======================================================= ========================================================
Further reading
---------------
For additional documentation, check :mod:`flask.ext.admin.form.rules` module source code (it is quite short) and
look at the `forms` example.
look at the `forms example <https://github.com/mrjoes/flask-admin/tree/master/examples/forms>`_ on GitHub.
Flask-Admin
===========
Flask-Admin is simple and extensible administrative interface framework for `Flask <http://flask.pocoo.org/>`_.
Flask-Admin is a batteries-included, simple-to-use `Flask <http://flask.pocoo.org/>`_ extension that lets you
add admin interfaces to Flask applications. It is inspired by the *django-admin* package, but implemented in such
a way that the developer has total control of the look, feel and functionality of the resulting application.
You can see some examples of how Flask-Admin can be used at `http://examples.flask-admin.org <http://examples.flask-admin.org/>`_.
Browse through the documentation below to learn more about what you can do with Flask-Admin. Or head over to
`our GitHub repository <http://github.com/mrjoes/flask-admin>`_ to find out how you can contribute to the project.
.. toctree::
:maxdepth: 2
......@@ -12,8 +19,8 @@ Flask-Admin is simple and extensible administrative interface framework for `Fla
localization
tips
db
form_rules
model_guidelines
form_rules
api/index
changelog
renamed_columns
......
Localization
============
Flask-Admin uses the `Flask-BabelEx <http://github.com/mrjoes/flask-babelex/>`_ package to handle translations.
Flask-BabelEx is a fork of Flask-Babel with following features:
Flask-Admin makes it possible for you to serve your application in more than one language. To do this, it makes use of
the `Flask-BabelEx <http://github.com/mrjoes/flask-babelex/>`_ package for handling translations. This package is a
fork of the popular `Flask-Babel <http://github.com/mitshuhiko/flask-babel/>`_ package, with the following features:
1. It is API-compatible with Flask-Babel
2. It allows distribution of translations with Flask extensions
3. Much more configurable
3. It aims to be more configurable than Flask-Babel
If Flask-Admin can not import Flask-BabelEx, it disables localization support completely.
Currently *Flask-BabelEx* is the only supported way of enabling localization support in Flask-Admin.
How to enable localization
--------------------------
1. Initialize Flask-BabelEx by creating instance of `Babel` class::
1. Install Flask-BabelEx::
pip install flask-babelex
2. Initialize Flask-BabelEx by creating instance of `Babel` class::
from flask import app
from flask.ext.babelex import Babel
......@@ -22,7 +26,7 @@ How to enable localization
app = Flask(__name__)
babel = Babel(app)
2. Create locale selector function::
3. Create a locale selector function::
@babel.localeselector
def get_locale():
......@@ -30,7 +34,9 @@ How to enable localization
# user profile, cookie, session, etc.
return 'en'
3. Initialize Flask-Admin as usual.
4. Initialize Flask-Admin as usual.
You can check `babel` example to see localization in action. To change locale, add *?en=<locale name>* to the URL. For example, URL
can look like: `http://localhost:5000/admin/userview/?lang=fr <http://localhost:5000/admin/userview/?lang=fr>`_.
You can check the `babel` example to see localization in action. When running this example, you can change the
locale simply by adding a query parameter, like *?en=<locale name>* to the URL. For example, a French version of
the application should be accessible at:
`http://localhost:5000/admin/userview/?lang=fr <http://localhost:5000/admin/userview/?lang=fr>`_.
......@@ -165,7 +165,6 @@ have access to the view in question::
def is_accessible(self):
return login.current_user.is_authenticated()
You can also implement policy-based security, conditionally allowing or disallowing access to parts of the
administrative interface. If a user does not have access to a particular view, the menu item won't be visible.
......
Working with templates
======================
Flask-Admin is built on top of standard Flask template management functionality.
One great advantage of building an extension on top of Flask, is the great templating engine that
comes with the package. Jinja2 allows you to use most of the Python syntax that you are used to, inside
of your templates, helping you generate either text or code in a powerful, yet flexible way.
If you're not familiar with Jinja2 templates, take a look `here <http://jinja.pocoo.org/docs/templates/>`_. Short summary:
To explore some more of what Jinja2 can offer you, head over to their documentation at
`http://jinja.pocoo.org/docs/ <http://jinja.pocoo.org/docs/>`_. But the most important features for you to
understand in order to get started with Flask-Admin are given below.
1. You can derive from template;
2. You can override template block(s);
3. When you override template block, you can render or not render parent block;
4. It does not matter how blocks are nested - you override them by name.
Inheritance
-----------
Templates can extend other templates. This enables you, for example, to build the standard components of
your site into a *base* template, where they are defined only once. This template can then be extended by
other templates, where more specific content may be added.
Flask Core
----------
Large applications may end up having several layers of templates, starting for example with a very general HTML
structure, and then growing more and more specific at each level, until the final layer of templates define unique
pages in the application. But it needs not be very complicated, and the majority of applications will only really
need a handful of well-designed templates.
All Flask-Admin templates should derive from `admin/master.html`.
Building blocks
---------------
`admin/master.html` is a proxy which points to `admin/base.html`. It contains following blocks:
With Jinja2, templates are made up of *blocks* of code, which define where a child template's contents fit into the
bigger picture, as defined by the parent template.
A parent template may define any number of these code blocks, and a child template may define content for any number
of those. So, by extending an existing template, you get to just fill-in the blanks, rather than having to deal
with lots of boilerplate code that is not really relevant to the problem at hand.
Power & Flexibility
-------------------
When a block is defined in a parent template, it can already be given some content, ensuring that something
will be rendered in that place, even if a child template chooses to ignore that block completely.
If content is defined in a child template, you have the option of also rendering the code that the parent template
may have defined in that block by calling::
{{ super() }}
anywhere inside that block. But the default behaviour is to simply override the block entirely.
Since these template blocks are defined by name, you have a lot of freedom in how you decide to arrange / nest them
in your code.
Jinja2 & Flask Admin
--------------------
Flask-Admin defines one *base* template at `admin/master.html` that all the other admin templates are derived
from. This template is a proxy which points to `admin/base.html`, which defines
the following blocks:
============== ========================================================================
Block Name Description
============== ========================================================================
head_meta Page metadata in the header
title Page title
......@@ -33,33 +71,52 @@ body Content (that's where your view will be displayed)
tail Empty area below content
============== ========================================================================
`admin/index.html` will be used display default `Home` admin page. By default it is empty.
Adding an Index Page
--------------------
Models
------
You'll notice that the 'Home' page that is created by Flask-Admin at `/admin` is largely empty. By default, the
only content on the page is a set of controls for navigating to the views that you have defined. You can change this by
creating a template at `admin/index.html` in your `templates` directory.
There are 3 main templates that are used to display models:
Working with your Models
------------------------
`admin/model/list.html` is list view template and contains following blocks:
By default, Flask-Admin uses three pre-defined templates for displaying your models in the admin-interface:
======================= ============================================
model_menu_bar Menu bar
model_list_table Table container
list_header Table header row
list_row_actions_header Actions header
list_row Single row
list_row_actions Row action cell with edit/remove/etc buttons
empty_list_message Message that will be displayed if there are no models found
======================= ============================================
* `admin/model/list.html`
* `admin/model/create.html`
* `admin/model/edit.html`
All three of these extend the `admin/master.html` template, and you can override them by defining your own templates,
with the same path relative to your `templates` folder.
You could also choose to extend these templates, rather than overriding them. In this case you will need to
point your classes at your own templates, rather than letting them use the defaults. For example, your own template
for the *edit* views could be defined in `templates/my_edit_template.html` to look something like::
{% extends 'admin/model/edit.html' %}
{% block tail %}
{{ super() }}
...
{% endblock %}
And your classes could be made to use this template by setting the appropriate class property::
class MyModelView(ModelView):
edit_template = 'my_edit_template.html'
The three available properties are simply called `list_template`, `create_template` and `edit_template`.
`admin/model/create.html` and `admin/model/edit.html` are used to display model creation editing forms respectively. They don't contain any custom
blocks and if you want to change something, you can do it using any of the blocks found in `admin/master.html`.
Environment variables
---------------------
There are few variables and methods that are always accessible in administrative templates:
While working in any of the templates that extend `admin/master.html`, you have access to a small number of
environment variables:
==================== ================================
Variable Name Description
==================== ================================
admin_view Current administrative view
admin_base_template Base template name
......@@ -72,10 +129,25 @@ h Helpers from :mod:`~flask.ext.admin.helpers` module
Customizing templates
---------------------
You can override any used template in your Flask application by creating template with same name and relative path in your main `templates` directory.
As noted earlier, you can override any default Flask-Admin template by creating your own template with same name and
relative path inside your own `templates` directory.
If you need to override master template, you can pass template name to the `Admin` constructor::
You can also override the master template, but then you need to pass your own template name to the `Admin`
constructor::
admin = Admin(app, base_template='my_master.html')
For model views, use `list_template`, `create_template` and `edit_template` properties to use non-default template.
In addition to all of the blocks that are inherited from `admin/master.html`, the `admin/model/list.html` template
also contains the following blocks:
======================= ============================================
Block Name Description
======================= ============================================
model_menu_bar Menu bar
model_list_table Table container
list_header Table header row
list_row_actions_header Actions header
list_row Single row
list_row_actions Row action cell with edit/remove/etc buttons
empty_list_message Message that will be displayed if there are no models found
======================= ============================================
\ No newline at end of file
......@@ -4,38 +4,42 @@ Usage Tips
General tips
------------
1. Whenever your administrative views share common functionality such as authentication,
form validation, make use of read-only views and so on - create your own base class which
inherits from proper Flask-Admin view class.
1. A reasonably obvious, but very useful, pattern is to wrap any shared functionality that your different admin views
might need into a base class that they can all inherit from (to help you keep things
`DRY <http://en.wikipedia.org/wiki/Don't_repeat_yourself>`_).
For example, if you need to check user permissions for every call, don't implement
`is_accessible` in every administrative view. Create your own base class, implement
`is_accessible` there and use this class for all your views.
For example, rather than manually checking user permissions in each of your admin views, you can implement a
base class such as ::
2. You can override used templates either by using `ModelView` properties (such as
`list_template`, `create_template`, `edit_template`) or
putting customized version of the template into your `templates/admin/` directory
class MyView(BaseView):
def is_accessible(self):
return login.current_user.is_authenticated()
3. If you need to customize look and feel of model forms, there are two options:
- Override create/edit template
- Use new :mod:`flask.ext.admin.form.rules` form rendering rules
and every view that inherits from this, will have the permission checking done automatically. The important thing
to notice, is that your base class needs to inherit from a built-in Flask-Admin view.
4. Flask-Admin has that manage file/image uploads and store result in model field. You can
find documentation here :mod:`flask.ext.admin.form.upload`.
2. You can override a default template either by passing the path to your own template in to the relevant `ModelView`
property (either `list_template`, `create_template` or `edit_template`) or by putting your own customized
version of a default template into your `templates/admin/` directory.
5. If you don't want to use Flask-Admin form scaffolding logic, you can override
:meth:`~flask.ext.admin.model.base.scaffold_form` and put your own form creation
logic there. For example, if you use `WTForms-Alchemy <https://github.com/kvesteri/wtforms-alchemy>`_, all you have to do
is to put appropriate form generation code into your `ModelView` class into the
`scaffold_form` method.
3. To customize the overall look and feel of the default model forms, you have two options: Either, you could
override the default create/edit templates. Or, alternatively, you could make use of the form rendering rules
(:mod:`flask.ext.admin.form.rules`) that were introduced in version 1.0.7.
4. To simplify the management of file uploads, Flask-Admin comes with a dedicated tool, for which you can find
documentation at: :mod:`flask.ext.admin.form.upload`.
5. If you don't want to the use the built-in Flask-Admin form scaffolding logic, you are free to roll your own
by simply overriding :meth:`~flask.ext.admin.model.base.scaffold_form`. For example, if you use
`WTForms-Alchemy <https://github.com/kvesteri/wtforms-alchemy>`_, you could put your form generation code
into a `scaffold_form` method in your `ModelView` class.
SQLAlchemy
----------
1. If `synonym_property` does not return SQLAlchemy field, Flask-Admin
won't be able to figure out what to do with it and won't generate form
field. In this case, you need to manually contribute field::
1. If the `synonym_property` does not return a SQLAlchemy field, then Flask-Admin won't be able to figure out what to
do with it, so it won't generate a form field. In this case, you would need to manually contribute your own field::
class MyView(ModelView):
def scaffold_form(self):
......@@ -46,5 +50,5 @@ SQLAlchemy
MongoEngine
-----------
1. Flask-Admin supports GridFS backed image and file uploads. Done through
WTForms fields and documentation can be found here :mod:`flask.ext.admin.contrib.mongoengine.fields`.
1. Flask-Admin supports GridFS-backed image- and file uploads, done through WTForms fields. Documentation can be found
at :mod:`flask.ext.admin.contrib.mongoengine.fields`.
......@@ -76,7 +76,7 @@ class RegistrationForm(form.Form):
# Initialize flask-login
def init_login():
login_manager = login.LoginManager()
login_manager.setup_app(app)
login_manager.init_app(app)
# Create user loader function
@login_manager.user_loader
......
......@@ -11,7 +11,7 @@ app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dummy.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample_db.sqlite'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
......@@ -53,13 +53,14 @@ def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
if __name__ == '__main__':
# Create admin with custom base template
admin = admin.Admin(app, base_template='layout.html')
# Create admin with custom base template
admin = admin.Admin(app, base_template='layout.html')
# Add views
admin.add_view(UserAdmin(User, db.session))
admin.add_view(CustomView(Page, db.session))
# Add views
admin.add_view(UserAdmin(User, db.session))
admin.add_view(CustomView(Page, db.session))
if __name__ == '__main__':
# Create DB
db.create_all()
......
{% extends 'admin/master.html' %}
{% block body %}
{{ super() }}
<div class="row-fluid">
<h1>Flask-Admin example</h1>
<p class="lead">
Customize the layout
</p>
<p>
This example shows how you can customize the look & feel of the admin interface.
</p>
<p>
This is done by overriding some of the built-in templates.
</p>
<a class="btn btn-primary" href="/"><i class="icon-arrow-left icon-white"></i> Back</a>
</div>
{% endblock body %}
\ No newline at end of file
......@@ -3,6 +3,11 @@ from flask.ext.admin import Admin
app = Flask(__name__)
app.debug = True
admin = Admin(app)
app.run(debug=True)
if __name__ == '__main__':
# Start app
app.run(debug=True)
......@@ -8,8 +8,12 @@ class MyView(BaseView):
return self.render('index.html')
app = Flask(__name__)
app.debug = True
admin = Admin(app)
admin.add_view(MyView(name='Hello'))
app.run(debug=True)
if __name__ == '__main__':
# Start app
app.run()
from flask import Flask
from flask.ext.admin import Admin, BaseView, expose
class MyView(BaseView):
@expose('/')
def index(self):
return self.render('index.html')
app = Flask(__name__)
app.debug = True
admin = Admin(app)
admin.add_view(MyView(name='Hello 1', endpoint='test1', category='Test'))
admin.add_view(MyView(name='Hello 2', endpoint='test2', category='Test'))
admin.add_view(MyView(name='Hello 3', endpoint='test3', category='Test'))
app.run(debug=True)
if __name__ == '__main__':
# Start app
app.run()
......@@ -22,20 +22,20 @@ class AnotherAdminView(admin.BaseView):
# Create flask app
app = Flask(__name__, template_folder='templates')
app.debug = True
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
# Create admin interface
admin = admin.Admin()
admin.add_view(MyAdminView(category='Test'))
admin.add_view(AnotherAdminView(category='Test'))
admin.init_app(app)
if __name__ == '__main__':
# Create admin interface
admin = admin.Admin()
admin.add_view(MyAdminView(category='Test'))
admin.add_view(AnotherAdminView(category='Test'))
admin.init_app(app)
# Start app
app.run(debug=True)
app.run()
{% extends 'admin/master.html' %}
{% block body %}
{{ super() }}
<div class="row-fluid">
<h1>Flask-Admin example</h1>
<p class="lead">
Simple admin views, not related to models.
</p>
<p>
This example shows how to add your own views to the admin interface. The views do not have to be associated
to any of your models, and you can fill them with whatever content you want.
</p>
<p>
By adding custom views to the admin interface, they become accessible through the <em>navbar</em> at the top.
</p>
<a class="btn btn-primary" href="/"><i class="icon-arrow-left icon-white"></i> Back</a>
</div>
{% endblock body %}
\ No newline at end of file
......@@ -13,7 +13,7 @@ app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample_db_2.sqlite'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
......@@ -22,6 +22,7 @@ db = SQLAlchemy(app)
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
class Car(db.Model):
__tablename__ = 'cars'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
......@@ -30,6 +31,7 @@ class Car(db.Model):
def __unicode__(self):
return self.desc
class Tyre(db.Model):
__tablename__ = 'tyres'
car_id = db.Column(db.Integer, db.ForeignKey('cars.id'), primary_key=True)
......@@ -37,19 +39,22 @@ class Tyre(db.Model):
car = db.relationship('Car', backref='tyres')
desc = db.Column(db.String(50))
class CarAdmin(sqla.ModelView):
column_display_pk = True
form_columns = ['id', 'desc']
class TyreAdmin(sqla.ModelView):
column_display_pk = True
form_columns = ['car', 'tyre_id', 'desc']
# Create admin
admin = admin.Admin(app, 'Simple Models')
admin.add_view(CarAdmin(Car, db.session))
admin.add_view(TyreAdmin(Tyre, db.session))
if __name__ == '__main__':
# Create admin
admin = admin.Admin(app, 'Simple Models')
admin.add_view(CarAdmin(Car, db.session))
admin.add_view(TyreAdmin(Tyre, db.session))
# Create DB
db.create_all()
......
......@@ -16,7 +16,7 @@ app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample_db.sqlite'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
......@@ -139,15 +139,16 @@ class TreeView(sqla.ModelView):
inline_models = (Tree,)
# Create admin
admin = admin.Admin(app, 'Simple Models')
# Add views
admin.add_view(UserAdmin(User, db.session))
admin.add_view(sqla.ModelView(Tag, db.session))
admin.add_view(PostAdmin(db.session))
admin.add_view(TreeView(Tree, db.session))
if __name__ == '__main__':
# Create admin
admin = admin.Admin(app, 'Simple Models')
# Add views
admin.add_view(UserAdmin(User, db.session))
admin.add_view(sqla.ModelView(Tag, db.session))
admin.add_view(PostAdmin(db.session))
admin.add_view(TreeView(Tree, db.session))
# Create DB
db.create_all()
......
{% extends 'admin/master.html' %}
{% block body %}
{{ super() }}
<div class="row-fluid">
<h1>Flask-Admin example</h1>
<p class="lead">
Basic SQLAlchemy model views.
</p>
<p>
This example shows how to add basic CRUD-views for your SQLAlchemy models.
</p>
<p>
The views are generated automatically, but it is perfectly possible to customize them to suit your needs.
</p>
<a class="btn btn-primary" href="/"><i class="icon-arrow-left icon-white"></i> Back</a>
</div>
{% endblock body %}
\ No newline at end of file
......@@ -6,6 +6,13 @@ from wtforms.fields.core import _unset_value
from . import widgets
def is_empty(file_object):
file_object.seek(0)
first_char = file_object.read(1)
file_object.seek(0)
return not bool(first_char)
class ModelFormField(fields.FormField):
"""
Customized ModelFormField for MongoEngine EmbeddedDocuments.
......@@ -54,7 +61,7 @@ class MongoFileField(fields.FileField):
field.delete()
return
if isinstance(self.data, FileStorage):
if isinstance(self.data, FileStorage) and not is_empty(self.data.stream):
if not field.grid_id:
func = field.put
else:
......
......@@ -545,7 +545,7 @@ class InlineModelConverter(InlineModelConverterBase):
reverse_prop = None
for prop in target_mapper.iterate_properties:
if hasattr(prop, 'direction') and prop.direction.name == 'MANYTOONE':
if hasattr(prop, 'direction'):
if issubclass(model, prop.mapper.class_):
reverse_prop = prop
break
......@@ -556,7 +556,7 @@ class InlineModelConverter(InlineModelConverterBase):
forward_prop = None
for prop in mapper.iterate_properties:
if hasattr(prop, 'direction') and prop.direction.name == 'ONETOMANY':
if hasattr(prop, 'direction'):
if prop.mapper.class_ == target_mapper.class_:
forward_prop = prop
break
......
......@@ -76,7 +76,7 @@ class InlineFieldList(FieldList):
_fake = type(str('_fake'), (object, ), {})
output = []
for field, data in itertools.izip(self.entries, candidates):
for field, data in zip(self.entries, candidates):
if not self.should_delete(field):
fake_obj = _fake()
fake_obj.data = data
......
......@@ -78,7 +78,7 @@
this.applyStyle = function($el, name) {
// Process converters first
for (var conv in fieldConverters) {
var fildConv = fieldConverters[conv];
var fieldConv = fieldConverters[conv];
if (fieldConv($el, name))
return true;
......@@ -185,10 +185,20 @@
self.applyStyle($el, $el.attr('data-role'));
});
};
/**
* Add a field converter for customizing styles
*
* @method addFieldConverter
* @param {converter} function($el, name)
*/
this.addFieldConverter = function(converter) {
fieldConverters.push(converter);
};
};
// Add live event handler
$('.fa-remove-field').live('click', function(e) {
// Add on event handler
$('body').on('click', '.fa-remove-field' , function(e) {
e.preventDefault();
var form = $(this).closest('.fa-inline-field');
......
# Simplified Chinese translations for Flask-Admin.
# Copyright (C) 2012 ChiChan
# Copyright (C) 2013 ChiChan
# This file is distributed under the same license as the Flask-Admin
# project.
# ChiChan <chichanww@gmail.com>, 2013.
#
# muzuiget <muzuiget@gmail.com>, 2013.
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Flask-Admin\n"
"Project-Id-Version: Flask-Admin 1.0.7\n"
"Report-Msgid-Bugs-To: chichanww@gmail.com\n"
"POT-Creation-Date: 2012-11-09 03:54+0200\n"
"PO-Revision-Date: 2012-12-30 18:45+0100\n"
"Last-Translator: ChiChan <chicyanww@gmail.com>\n"
"POT-Creation-Date: 2013-10-26 16:49+0800\n"
"PO-Revision-Date: 2013-10-26 17:27+0800\n"
"Last-Translator: muzuiget <muzuiget@gmail.com>\n"
"Language-Team: \n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;\n"
"Generated-By: Babel 0.9.6\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Generated-By: Babel 1.3\n"
#: ../flask_admin/base.py:283
#: ../flask_admin/base.py:335
msgid "Home"
msgstr "首页"
#: ../flask_admin/form.py:83
msgid "Invalid time format"
msgstr "时间格式错误"
#: ../flask_admin/contrib/fileadmin.py:33
msgid "Invalid directory name"
msgstr "文件夹名称错误"
msgstr "无效文件夹名"
#: ../flask_admin/contrib/fileadmin.py:41
msgid "File to upload"
......@@ -38,216 +33,316 @@ msgstr "要上传的文件"
#: ../flask_admin/contrib/fileadmin.py:50
msgid "File required."
msgstr "文件是必须上传的。"
msgstr "请上传有效的文件。"
#: ../flask_admin/contrib/fileadmin.py:55
msgid "Invalid file type."
msgstr "不允许的文件格式。"
msgstr "不允许的文件类型。"
#: ../flask_admin/contrib/fileadmin.py:365
#: ../flask_admin/contrib/fileadmin.py:59
msgid "Content"
msgstr "内容"
#: ../flask_admin/contrib/fileadmin.py:481
msgid "File uploading is disabled."
msgstr "上传文件的功能已被禁用。"
msgstr "文件上传功能已被禁用。"
#: ../flask_admin/contrib/fileadmin.py:374
#: ../flask_admin/contrib/fileadmin.py:494
#, python-format
msgid "File \"%(name)s\" already exists."
msgstr "文件 \"%(name)s\" 已经存在。"
msgstr "文件 %(name)s 已经存在。"
#: ../flask_admin/contrib/fileadmin.py:381
#: ../flask_admin/contrib/fileadmin.py:502
#, python-format
msgid "Failed to save file: %(error)s"
msgstr "保存文件时发生异常:%(error)s"
msgstr "保存文件失败:%(error)s"
#: ../flask_admin/contrib/fileadmin.py:400
#: ../flask_admin/contrib/fileadmin.py:521
msgid "Directory creation is disabled."
msgstr "创建文件夹的功能已被禁用。"
msgstr "文件夹创建功能已被禁用。"
#: ../flask_admin/contrib/fileadmin.py:410
#: ../flask_admin/contrib/fileadmin.py:536
#, python-format
msgid "Failed to create directory: %(error)s"
msgstr "创建文件夹时发生异常: %(error)s"
msgstr "创建文件夹失败:%(error)s"
#: ../flask_admin/contrib/fileadmin.py:432
#: ../flask_admin/contrib/fileadmin.py:558
msgid "Deletion is disabled."
msgstr "删除功能已被禁用。"
msgstr "删除功能已被禁用。"
#: ../flask_admin/contrib/fileadmin.py:437
#: ../flask_admin/contrib/fileadmin.py:567
msgid "Directory deletion is disabled."
msgstr "删除文件夹功能已被禁用。"
msgstr "删除文件夹功能已被禁用。"
#: ../flask_admin/contrib/fileadmin.py:442
#: ../flask_admin/contrib/fileadmin.py:573
#, python-format
msgid "Directory \"%s\" was successfully deleted."
msgstr "删除文件夹 \"%s\" 成功。"
msgstr "删除文件夹 %s 成功。"
#: ../flask_admin/contrib/fileadmin.py:444
#: ../flask_admin/contrib/fileadmin.py:575
#, python-format
msgid "Failed to delete directory: %(error)s"
msgstr "删除文件夹时发生异常:%(error)s"
msgstr "删除文件夹失败:$(error)s"
#: ../flask_admin/contrib/fileadmin.py:448
#: ../flask_admin/contrib/fileadmin.py:511
#: ../flask_admin/contrib/fileadmin.py:580
#: ../flask_admin/contrib/fileadmin.py:717
#, python-format
msgid "File \"%(name)s\" was successfully deleted."
msgstr "删除文件 \"%(name)s\" 成功。"
msgstr "删除文件 %(name)s 成功。"
#: ../flask_admin/contrib/fileadmin.py:450
#: ../flask_admin/contrib/fileadmin.py:513
#: ../flask_admin/contrib/fileadmin.py:582
#: ../flask_admin/contrib/fileadmin.py:719
#, python-format
msgid "Failed to delete file: %(name)s"
msgstr "删除文件时发生异常:%(name)s"
msgstr "删除文件 %(name)s 失败"
#: ../flask_admin/contrib/fileadmin.py:469
#: ../flask_admin/contrib/fileadmin.py:601
msgid "Renaming is disabled."
msgstr "重命名已被禁用。"
msgstr "重命名功能已被禁用。"
#: ../flask_admin/contrib/fileadmin.py:473
#: ../flask_admin/contrib/fileadmin.py:609
msgid "Path does not exist."
msgstr "路径不存在。"
#: ../flask_admin/contrib/fileadmin.py:484
#: ../flask_admin/contrib/fileadmin.py:621
#, python-format
msgid "Successfully renamed \"%(src)s\" to \"%(dst)s\""
msgstr "将 \"%(src)s\" 重命名为 \"%(dst)s\"的操作成功完成。"
msgstr "重命名文件 %(src)s 为 %(dst)s 成功"
#: ../flask_admin/contrib/fileadmin.py:487
#: ../flask_admin/contrib/fileadmin.py:624
#, python-format
msgid "Failed to rename: %(error)s"
msgstr "重命名时发生异常:%(error)s"
msgstr "重命名文件失败:%(error)s"
#: ../flask_admin/contrib/fileadmin.py:503
#: ../flask_admin/contrib/peewee/view.py:355
#: ../flask_admin/contrib/sqla/view.py:680
#: ../flask_admin/contrib/fileadmin.py:667
#, python-format
msgid "Error saving changes to %(name)s."
msgstr "保存修改到 %(name)s 出现错误。"
#: ../flask_admin/contrib/fileadmin.py:671
#, python-format
msgid "Changes to %(name)s saved successfully."
msgstr "保存修改到 %(name)s 成功。"
#: ../flask_admin/contrib/fileadmin.py:678
#, python-format
msgid "Error reading %(name)s."
msgstr "读取 %(name)s 错误。"
#: ../flask_admin/contrib/fileadmin.py:681
#: ../flask_admin/contrib/fileadmin.py:690
#, python-format
msgid "Unexpected error while reading from %(name)s"
msgstr "读取文件文件 %(name)s 出现未知错误"
#: ../flask_admin/contrib/fileadmin.py:687
#, python-format
msgid "Cannot edit %(name)s."
msgstr "无法编辑 %(name)s。"
#: ../flask_admin/contrib/fileadmin.py:704
#: ../flask_admin/contrib/mongoengine/view.py:571
#: ../flask_admin/contrib/peewee/view.py:405
#: ../flask_admin/contrib/pymongo/view.py:329
#: ../flask_admin/contrib/sqla/view.py:868
msgid "Delete"
msgstr "删除"
#: ../flask_admin/contrib/fileadmin.py:504
#: ../flask_admin/contrib/fileadmin.py:705
msgid "Are you sure you want to delete these files?"
msgstr "您确定要删除这些文件吗?"
msgstr "你打算要删除这些文件吗?"
#: ../flask_admin/contrib/fileadmin.py:708
msgid "File deletion is disabled."
msgstr "删除文件功能已被禁用"
#: ../flask_admin/contrib/fileadmin.py:721
msgid "Edit"
msgstr "编辑"
#: ../flask_admin/contrib/rediscli.py:125
msgid "Cli: Invalid command."
msgstr "Cli:无效命令。"
#: ../flask_admin/contrib/mongoengine/filters.py:36
#: ../flask_admin/contrib/peewee/filters.py:35
#: ../flask_admin/contrib/sqla/filters.py:35
#: ../flask_admin/contrib/pymongo/filters.py:38
#: ../flask_admin/contrib/sqla/filters.py:36
msgid "equals"
msgstr "等于"
#: ../flask_admin/contrib/mongoengine/filters.py:45
#: ../flask_admin/contrib/peewee/filters.py:43
#: ../flask_admin/contrib/sqla/filters.py:43
#: ../flask_admin/contrib/pymongo/filters.py:47
#: ../flask_admin/contrib/sqla/filters.py:44
msgid "not equal"
msgstr "不等于"
#: ../flask_admin/contrib/mongoengine/filters.py:55
#: ../flask_admin/contrib/peewee/filters.py:52
#: ../flask_admin/contrib/sqla/filters.py:52
#: ../flask_admin/contrib/pymongo/filters.py:57
#: ../flask_admin/contrib/sqla/filters.py:53
msgid "contains"
msgstr "包含"
#: ../flask_admin/contrib/mongoengine/filters.py:65
#: ../flask_admin/contrib/peewee/filters.py:61
#: ../flask_admin/contrib/sqla/filters.py:61
#: ../flask_admin/contrib/pymongo/filters.py:67
#: ../flask_admin/contrib/sqla/filters.py:62
msgid "not contains"
msgstr "不包含"
#: ../flask_admin/contrib/mongoengine/filters.py:74
#: ../flask_admin/contrib/peewee/filters.py:69
#: ../flask_admin/contrib/sqla/filters.py:69
#: ../flask_admin/contrib/pymongo/filters.py:76
#: ../flask_admin/contrib/sqla/filters.py:70
msgid "greater than"
msgstr "大于"
#: ../flask_admin/contrib/mongoengine/filters.py:83
#: ../flask_admin/contrib/peewee/filters.py:77
#: ../flask_admin/contrib/sqla/filters.py:77
#: ../flask_admin/contrib/pymongo/filters.py:85
#: ../flask_admin/contrib/sqla/filters.py:78
msgid "smaller than"
msgstr "小于"
#: ../flask_admin/contrib/peewee/view.py:317
#: ../flask_admin/contrib/sqla/view.py:627
#: ../flask_admin/contrib/mongoengine/view.py:462
#, python-format
msgid "Failed to get model. %(error)s"
msgstr "获取 model 失败。%(error)s"
#: ../flask_admin/contrib/mongoengine/view.py:483
#: ../flask_admin/contrib/peewee/view.py:355
#: ../flask_admin/contrib/pymongo/view.py:264
#: ../flask_admin/contrib/sqla/view.py:801
#, python-format
msgid "Failed to create model. %(error)s"
msgstr "创建模型时发生异常:%(error)s"
msgstr "创建 model 失败。%(error)s"
#: ../flask_admin/contrib/peewee/view.py:332
#: ../flask_admin/contrib/sqla/view.py:647
#: ../flask_admin/contrib/mongoengine/view.py:510
#: ../flask_admin/contrib/peewee/view.py:375
#: ../flask_admin/contrib/pymongo/view.py:289
#: ../flask_admin/contrib/sqla/view.py:827
#, python-format
msgid "Failed to update model. %(error)s"
msgstr "更新模型时发生异常:%(error)s"
msgstr "更新 model 失败。%(error)s"
#: ../flask_admin/contrib/peewee/view.py:342
#: ../flask_admin/contrib/sqla/view.py:666
#: ../flask_admin/contrib/mongoengine/view.py:535
#: ../flask_admin/contrib/peewee/view.py:392
#: ../flask_admin/contrib/pymongo/view.py:315
#: ../flask_admin/contrib/sqla/view.py:854
#, python-format
msgid "Failed to delete model. %(error)s"
msgstr "删除模型时发生异常:%(error)s"
msgstr "删除 model 失败。%(error)s"
#: ../flask_admin/contrib/peewee/view.py:356
#: ../flask_admin/contrib/sqla/view.py:681
#: ../flask_admin/contrib/mongoengine/view.py:572
#: ../flask_admin/contrib/peewee/view.py:406
#: ../flask_admin/contrib/pymongo/view.py:330
#: ../flask_admin/contrib/sqla/view.py:869
msgid "Are you sure you want to delete selected models?"
msgstr "您确定要删除这些模型?"
msgstr "你打算要删除这些 model 吗?"
#: ../flask_admin/contrib/peewee/view.py:372
#: ../flask_admin/contrib/sqla/view.py:699
#: ../flask_admin/contrib/mongoengine/view.py:581
#: ../flask_admin/contrib/peewee/view.py:422
#: ../flask_admin/contrib/pymongo/view.py:340
#: ../flask_admin/contrib/sqla/view.py:886
#, python-format
msgid "Model was successfully deleted."
msgid_plural "%(count)s 个模型已成功删除。"
msgstr[0] "删除已成功完成。"
#: ../flask_admin/contrib/peewee/view.py:377
#: ../flask_admin/contrib/sqla/view.py:704
msgid_plural "%(count)s models were successfully deleted."
msgstr[0] "删除 model 成功。"
msgstr[1] "%(count)s 个 model 已被删除。"
#: ../flask_admin/contrib/mongoengine/view.py:589
#: ../flask_admin/contrib/peewee/view.py:430
#: ../flask_admin/contrib/pymongo/view.py:345
#: ../flask_admin/contrib/sqla/view.py:894
#, python-format
msgid "Failed to delete models. %(error)s"
msgstr "删除模型时发生异常:%(error)s"
msgstr "删除 model 失败。%(error)s"
#: ../flask_admin/contrib/sqla/fields.py:125
#: ../flask_admin/contrib/sqla/fields.py:175
#: ../flask_admin/contrib/sqla/fields.py:180
#: ../flask_admin/contrib/sqla/fields.py:121
#: ../flask_admin/contrib/sqla/fields.py:171
#: ../flask_admin/contrib/sqla/fields.py:176 ../flask_admin/model/fields.py:163
#: ../flask_admin/model/fields.py:212
msgid "Not a valid choice"
msgstr "选择的值不正确。"
msgstr "选择的值无效"
#: ../flask_admin/contrib/sqla/validators.py:33
#: ../flask_admin/contrib/sqla/validators.py:34
msgid "Already exists."
msgstr "数据已经存在。"
msgstr "已经存在。"
#: ../flask_admin/form/fields.py:67
msgid "Invalid time format"
msgstr "无效时间格式"
#: ../flask_admin/form/fields.py:111
msgid "Invalid Choice: could not coerce"
msgstr "无效选择的值:强制格式转换失败"
#: ../flask_admin/form/upload.py:182
msgid "Invalid file extension"
msgstr "无效文件扩展名"
#: ../flask_admin/model/base.py:869
#: ../flask_admin/model/base.py:935
msgid "There are no items in the table."
msgstr "表中没有任何记录"
#: ../flask_admin/model/base.py:1199
msgid "Model was successfully created."
msgstr "模型创建成功。"
msgstr "创建 model 成功。"
#: ../flask_admin/model/base.py:1234
msgid "Model was successfully saved."
msgstr "保存 model 成功"
#: ../flask_admin/model/filters.py:82
#: ../flask_admin/model/filters.py:86
msgid "Yes"
msgstr "是"
#: ../flask_admin/model/filters.py:83
#: ../flask_admin/model/filters.py:87
msgid "No"
msgstr "否"
#: ../flask_admin/templates/admin/actions.html:3
#: ../flask_admin/templates/admin/actions.html:2
msgid "With selected"
msgstr "选中的"
#: ../flask_admin/templates/admin/lib.html:117
#: ../flask_admin/templates/admin/lib.html:147
msgid "Submit"
msgstr "提交"
#: ../flask_admin/templates/admin/lib.html:122
#: ../flask_admin/templates/admin/lib.html:152
msgid "Cancel"
msgstr "取消"
#: ../flask_admin/templates/admin/file/list.html:8
#: ../flask_admin/templates/admin/file/edit.html:5
#, python-format
msgid "You are editing %(path)s"
msgstr "你正在编辑 %(path)s"
#: ../flask_admin/templates/admin/file/list.html:9
msgid "Root"
msgstr ""
msgstr "Root"
#: ../flask_admin/templates/admin/file/list.html:55
#: ../flask_admin/templates/admin/file/list.html:62
#, python-format
msgid "Are you sure you want to delete \\'%(name)s\\' recursively?"
msgstr "您确定要递归删除 \\'%(name)s\\' 吗?"
msgstr "你打算递归地删除 %(name)s 吗?"
#: ../flask_admin/templates/admin/file/list.html:63
#: ../flask_admin/templates/admin/file/list.html:70
#, python-format
msgid "Are you sure you want to delete \\'%(name)s\\'?"
msgstr "您确定要删除 \\'%(name)s\\' 吗?"
msgstr "你打算删除 %(name)s 吗?"
#: ../flask_admin/templates/admin/file/list.html:90
#: ../flask_admin/templates/admin/file/list.html:101
msgid "Upload File"
msgstr "上传文件"
#: ../flask_admin/templates/admin/file/list.html:95
#: ../flask_admin/templates/admin/file/list.html:106
msgid "Create Directory"
msgstr "创建文件夹"
#: ../flask_admin/templates/admin/file/list.html:109
#: ../flask_admin/templates/admin/file/list.html:123
msgid "Please select at least one file."
msgstr "请至少选择一个文件。"
......@@ -256,53 +351,58 @@ msgstr "请至少选择一个文件。"
msgid "Please provide new name for %(name)s"
msgstr "请输入 %(name)s 的新名字"
#: ../flask_admin/templates/admin/model/create.html:12
#: ../flask_admin/templates/admin/model/list.html:13
#: ../flask_admin/templates/admin/model/create.html:5
msgid "Save and Add"
msgstr "保存并继续创建"
#: ../flask_admin/templates/admin/model/create.html:17
#: ../flask_admin/templates/admin/model/list.html:16
msgid "List"
msgstr "列表"
#: ../flask_admin/templates/admin/model/create.html:15
#: ../flask_admin/templates/admin/model/list.html:17
#: ../flask_admin/templates/admin/model/create.html:20
#: ../flask_admin/templates/admin/model/list.html:20
msgid "Create"
msgstr "创建"
#: ../flask_admin/templates/admin/model/create.html:20
msgid "Save and Add"
msgstr "保存并继续"
#: ../flask_admin/templates/admin/model/edit.html:5
msgid "Save and Continue"
msgstr "保存并继续编辑"
#: ../flask_admin/templates/admin/model/inline_form_list.html:24
#: ../flask_admin/templates/admin/model/inline_list_base.html:9
msgid "Delete?"
msgstr "删除?"
#: ../flask_admin/templates/admin/model/inline_form_list.html:32
#: ../flask_admin/templates/admin/model/inline_list_base.html:27
msgid "Add"
msgstr "增加"
#: ../flask_admin/templates/admin/model/list.html:24
#: ../flask_admin/templates/admin/model/layout.html:3
msgid "Add Filter"
msgstr "新增筛选器"
#: ../flask_admin/templates/admin/model/list.html:51
msgid "Search"
msgstr "搜索"
#: ../flask_admin/templates/admin/model/list.html:64
#: ../flask_admin/templates/admin/model/layout.html:17
msgid "Apply"
msgstr "应用"
#: ../flask_admin/templates/admin/model/list.html:66
#: ../flask_admin/templates/admin/model/layout.html:19
msgid "Reset Filters"
msgstr "重置筛选器"
msgstr "重置"
#: ../flask_admin/templates/admin/model/list.html:74
#: ../flask_admin/templates/admin/model/layout.html:28
msgid "Remove Filter"
msgstr "去除筛选器"
msgstr "移除"
#: ../flask_admin/templates/admin/model/layout.html:68
#: ../flask_admin/templates/admin/model/layout.html:75
msgid "Search"
msgstr "搜索"
#: ../flask_admin/templates/admin/model/list.html:149
#: ../flask_admin/templates/admin/model/list.html:110
msgid "You sure you want to delete this item?"
msgstr "你确定要删除这个东西吗?"
msgstr "你打算删除这条记录?"
#: ../flask_admin/templates/admin/model/list.html:173
#: ../flask_admin/templates/admin/model/list.html:146
msgid "Please select at least one model."
msgstr "请至少选择一个模型。"
msgstr "请至少选择一个 model。"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment