Во-первых, я знаю, что здесь есть десятки подобных вопросов. Я просмотрел большинство, если не все из них, и ни один из них не помог мне найти решение. Следующий вопрос является наиболее похожим, но моя реализация «dynamic» немного отличается от их (подробнее об этом ниже): Проверка Flask / Python / WTForms и динамическая установка выбора SelectField
Вкратце:
У меня есть форма, которая используется для запроса отчета из созданного мной инструмента мониторинга сети. Инструмент отслеживает все виды статистики для различных беспроводных сетей. Вот определение класса формы. Моим динамическим полем является ssidFilter selectField.
class RequestReportForm(FlaskForm):
startDate = DateField('Start Date', validators=[DataRequired(), validate_startDate])
startTime = TimeField('Start Time', format='%H:%M', validators=[DataRequired()])
endDate = DateField('End Date', format='%Y-%m-%d', validators=[DataRequired(), validate_endDate])
endTime = TimeField('End Time', format='%H:%M', validators=[DataRequired(), validate_allDates])
ssidFilter = SelectField('SSID', default=('All', 'All'))
reportType = SelectField('Report Type', validators = [DataRequired()], choices=[
('rssi', 'RSSI vs. Time'),
('snr', 'SNR vs. Time'),
('ClientCount', 'Client Count vs. Time'),
])
selectLocation = SelectField('Locations', validators = [DataRequired()], choices=[
('All','All'),
('mainLobby', 'Main Lobby'),
('level1', 'Level 1'),
('level2', 'Level 2'),
])
submit = SubmitField('Generate Report')
Я уже реализовал Javascript, чтобы взять введенные пользователем поля startDate и endDate и выполнить запрос к моей базе данных, "выбрав" другой маршрут фляги в моемприложение, чтобы вернуть список всех беспроводных сетей (SSID), которые были использованы в диапазоне дат, которые они ввели. Вот этот маршрут:
@app.route('/updateSSIDs/<startDate>/<endDate>', methods=['GET'])
def updateSSIDs(startDate, endDate):
startDate = datetime.strptime(startDate, '%Y-%m-%d')
endDate = datetime.strptime(endDate, '%Y-%m-%d')
# Get a list of unique SSIDs that we have data for between the start and end dates selected on the form.
SSIDs = getSSIDs(startDate, endDate)
SSIDArray = []
for ssid_tuple in SSIDs:
ssidObj = {}
ssidObj['id'] = ssid_tuple[0]
ssidObj['ssid'] = ssid_tuple[0]
SSIDArray.append(ssidObj)
return jsonify({'SSIDs' : SSIDArray})
Переменная SSIDArray
выглядит так, как она до jsonify'd:
[{'id': 'Example Network 1', 'ssid': 'Example Network 1'}, {'id': 'Staff', 'ssid': 'Staff'}, ... ]
Вот как я создаю экземпляр формы:
@app.route('/requestReport', methods=['GET', 'POST'])
def requestReport():
form = RequestReportForm()
form.ssidFilter.choices = getSSIDs(datetime.now(), datetime.now())
if form.validate_on_submit():
print("Valid form data:")
print(form.data)
flash(f'Received request for report from {form.startDate.data} at {form.startTime.data} through {form.endDate.data} at {form.endTime.data}', 'success')
startDate = form.startDate.data
startTime = form.startTime.data
endDate = form.endDate.data
endTime = form.endTime.data
reportType = form.reportType.data
locations = form.selectLocation.data
ssid = form.ssidFilter.data
# Put requested times into datetime objects
startDateTime = datetime(startDate.year, startDate.month, startDate.day, startTime.hour, startTime.minute)
endDateTime = datetime(endDate.year, endDate.month, endDate.day, endTime.hour, endTime.minute)
# Generate report and redirect client to report.
reportParameters = rpt.prepareReport_single(startDateTime, endDateTime, reportType, locations, ssid)
report = rpt.buildReport_singleLocation(reportParameters)
report = Markup(report)
return render_template('viewReport.html', value=report)
Обратите внимание, что я заполняю свое динамическое поле, здесь form.ssidFilter.choices
, вызывая ту же самую функцию getSSIDs
, которая отвечает на мой вызов выборки Javascript, но я передаю datetime.now()
как для начала, так и дляДата окончания. Это должно сначала показать пользователю список беспроводных сетей, которые в настоящее время используются, но как только они изменят даты, список обновится с другим набором сетей.
И в этом заключается проблема:Как я могу настроить список допустимых вариантов (form.ssidFilter.choices
), чтобы он содержал список сетей, который возвращается после того, как клиент вводит даты для отчета?
Возможные решения, которые я изучаю:
Перезагрузка страницы после выбора даты для создания новой формы с динамическими данными.
Сначала сохраните огромный список всех доступных вариантов, а затемвыбор будет динамически фильтроваться через JS, когда пользователь изменяет даты в форме.
О, и форма отлично работает, если выбранный SSID является SSID, который был в списке из оператора form.ssidFilter.choices = getSSIDs(datetime.now(), datetime.now())
. Эта проблема возникает только тогда, когда выбран элемент, которого изначально не было в списке вариантов (что имеет смысл - я просто не знаю, как его решить).
Спасибо за потраченное время.
РЕДАКТИРОВАТЬ / Решение:
Благодаря ответу @ SuperShoot я смог заставить это работать. Для меня ключевым было сделать так, чтобы маршрут Flask различал тип HTTP-запроса - GET или POST. Поскольку я знал, что метод GET используется только для извлечения формы, а метод POST - только для отправки заполненной формы, я мог извлечь выборки startDate и endDate от пользователя, выполнить запрос для получения данных и обновитьполе choices
из моего класса формы.
Мне пришлось провести дополнительную проверку, как и в @SuperShoot, но я сделал это немного по-другому. Поскольку мой код JavaScript вызывает отдельный маршрут из моего приложения Flask, как только изменяется дата окончания, форма не несет ответственности за проверку выбранной даты. Я реализовал некоторую проверку в этом другом маршруте Flask.
Вот мой измененный маршрут Flask requestReport
:
@app.route('/requestReport', methods=['GET', 'POST'])
def requestReport():
form = RequestReportForm()
form.ssidFilter.choices = getSSIDs(datetime.now(), datetime.now())
if request.method == 'POST':
startDate = datetime(form.startDate.data.year, form.startDate.data.month, form.startDate.data.day)
endDate = datetime(form.endDate.data.year, form.endDate.data.month, form.endDate.data.day)
# Update acceptable choices for the SSIDs on the form if the form is submitted.
form.ssidFilter.choices = getSSIDs(startDate, endDate)
if form.validate_on_submit():
flash(f'Received request for report from {form.startDate.data} at {form.startTime.data} through {form.endDate.data} at {form.endTime.data}', 'success')
startDate = form.startDate.data
startTime = form.startTime.data
endDate = form.endDate.data
endTime = form.endTime.data
reportType = form.reportType.data
locations = form.selectLocation.data
ssid = form.ssidFilter.data
# Put requested times into datetime objects
startDateTime = datetime(startDate.year, startDate.month, startDate.day, startTime.hour, startTime.minute)
endDateTime = datetime(endDate.year, endDate.month, endDate.day, endTime.hour, endTime.minute)
# Generate report and redirect client to report.
reportParameters = rpt.prepareReport_single(startDateTime, endDateTime, reportType, locations, ssid)
report = rpt.buildReport_singleLocation(reportParameters)
report = Markup(report)
return render_template('viewReport.html', value=report)
else:
return render_template('requestReport.html', title='Report Request', form=form)
А вот мой обновленный маршрут updateSSIDs
, который вызывается через Javascript, когдадата окончания формы изменяется:
@app.route('/updateSSIDs/<startDate>/<endDate>', methods=['GET'])
def updateSSIDs(startDate, endDate):
startDate = datetime.strptime(startDate, '%Y-%m-%d')
endDate = datetime.strptime(endDate, '%Y-%m-%d')
# Validate startDate and endDate
emptyDataSet = {'SSIDs' : {'id ': 'All', 'ssid' : 'All'}}
if startDate > endDate:
return jsonify(emptyDataSet)
if startDate >= datetime.now():
return jsonify(emptyDataSet)
if startDate.year not in range(2019, 2029) or endDate.year not in range(2019, 2029):
return jsonify(emptyDataSet)
# Get a list of unique SSIDs that we have data for between the start and end dates selected on the form.
SSIDs = getSSIDs(startDate, endDate)
SSIDArray = []
for ssid_tuple in SSIDs:
ssidObj = {}
ssidObj['id'] = ssid_tuple[0]
ssidObj['ssid'] = ssid_tuple[0]
SSIDArray.append(ssidObj)
return jsonify({'SSIDs' : SSIDArray})
Этот маршрут выполняет некоторые базовые проверки, чтобы убедиться, что отправленные даты не являются полностью нелепыми, прежде чем пытаться получить данные из базы данных с помощью getSSIDs
, но я делаюнемного более тщательной проверки в функции getSSIDs
.