Я создал собственное представление «Расширенный поиск», немного расширив представление индекса администратора фляги. Это приводит пользователя к пользовательской форме, отображаемой с использованием механизма рендеринга формы администратора flask, чтобы выполнить большую часть работы.
Форма определяется следующим образом:
class PaperSearchForm(FlaskForm):
return_url = HiddenField()
title = StringField()
abstract = StringField()
start_date = DateTimeField()
end_date = DateTimeField()
doi = StringField()
pubmed_id = StringField()
link = StringField()
journals = QuerySelectMultipleField(
query_factory=_get_model(Journal),
)
authors = QuerySelectMultipleField(
query_factory=_get_model(Author),
)
keywords = QuerySelectMultipleField(
query_factory=_get_model(Keyword),
)
chapters = QuerySelectMultipleField(
query_factory=_get_model(Chapter),
)
printed = BooleanField(default=True)
unprinted = BooleanField(default=True)
submit = SubmitField('Search')
Представление модели расширенного поиска определяется следующим образом:
from flask import flash
from flask import redirect
from flask import request
from flask_admin import BaseView
from flask_admin import expose
from flask_wtf import FlaskForm
from flask_login import current_user
from .forms import PaperSearchForm
class AdvancedPaperSearchView(BaseView):
form_base_class = FlaskForm
def __init__(self,
name=None,
category=None,
endpoint=None,
url=None,
template='auth/model/paper/advanced_search.html',
menu_class_name=None,
menu_icon_type=None,
menu_icon_value=None
):
super(AdvancedPaperSearchView, self).__init__(
name,
category,
endpoint,
url or '/',
'static',
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
self._template = template
def is_visible(self):
return False
def is_accessible(self):
if current_user.is_authenticated:
return current_user.can_view_papers()
return False
@expose('/', methods=['GET', 'POST'])
def index(self):
form = PaperSearchForm()
form.return_url.data = request.args['return_url']
self._template_args['form'] = form
self._template_args['cancel_url'] = request.args['return_url']
return self.render(self._template)
@expose('/search', methods=['POST'])
def search(self):
# List view generates list of models based on 'term'= from request.args.get('term', default=None)
# Manually setting these arguments will serve as the advanced search functionality
form = PaperSearchForm() # ???
search = None # ???
filter = None # ???
flash('How to apply multiple filters?', 'error')
return redirect('papermodelview.index', search=search, filter=filter) # ???
Затем шаблон определяется следующим образом:
{% extends "admin/master.html" %}
{% import 'admin/lib.html' as lib with context %}
{% from 'admin/lib.html' import extra with context %} {# backward compatible #}
{% from 'admin/lib.html' import render_field with context %}
{% block head %}
{{ super() }}
{{ lib.form_css() }}
{% endblock %}
{% block body %}
{% block navlinks %}
<ul class="nav nav-tabs">
<li>
<a href="{{ return_url }}">List</a>
</li>
<li class="active">
<a href="javascript:void(0)">Advanced Search</a>
</li>
</ul>
{% endblock %}
<form method="post" action="{{ url_for('advancedpapersearchview.search') }}">
{{ form.return_url }}
{{ form.csrf_token }}
{{ render_field(form, form.title) }}
{{ render_field(form, form.abstract) }}
{{ render_field(form, form.start_date) }}
{{ render_field(form, form.end_date) }}
{{ render_field(form, form.doi) }}
{{ render_field(form, form.pubmed_id) }}
{{ render_field(form, form.link) }}
{{ render_field(form, form.journals) }}
{{ render_field(form, form.authors) }}
{{ render_field(form, form.chapters) }}
{{ render_field(form, form.keywords) }}
{{ render_field(form, form.printed) }}
{{ render_field(form, form.unprinted) }}
<div class="row">
<div class="col-xs-12">
{{ form.submit(class="btn") }}
</div>
</div>
<div class="row">
<div class="col-xs-12">
<a href="{{ cancel_url }}" class="btn warning">
Cancel
</a>
</div>
</div>
</form>
{% endblock %}
{% block tail %}
{{ super() }}
{{ lib.form_js() }}
<script src="/static/vendor/jquery.min.js" type="text/javascript">/script>
{# use /static/bootstrap2/js/bootstrap.min.js if you are using bootstrap2 #}
<script src="/static/bootstrap3/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/static/vendor/moment.min.js" type="text/javascript"></script>
<script src="/static/vendor/select2/select2.min.js" type="text/javascript"></script>
{% endblock %}
В представлении бумажной модели фильтры определяются следующим образом:
class PaperModelView(MainModelView):
# ...
column_filters = [
'chapter_paper_assoc.printed',
'journal_paper_assoc.publication_date',
'chapters.name',
'chapters.number',
'journals.name',
'authors.last_name',
'keywords.keyword',
]
Итак, я прокомментировал кучу ??? где я не знаю, что делать. Как мне сопоставить поля моей формы (конкретные атрибуты выбранных моделей) с фильтрами, которые определены «column_filters» в представлении модели.
То есть вместо того, чтобы переопределять обработку поиска в представлении индекса для фактического выполнения поиска, я мог бы вместо этого применить набор фильтров, передав эту информацию в представление индекса, которое извлекает эту информацию с помощью:
filters=response.args.get('filter', None)
Есть ли лучший подход?
Спасибо