우선, 여기에 유사한 질문이 수십 개 있다는 것을 알고 있습니다. 나는 전부는 아니지만 대부분을 보았고 그들 중 어느 것도 나를 해결책으로 인도하지 못했습니다. 다음 질문은 가장 유사하지만 "동적"구현은 해당 질문과 약간 다릅니다 (아래에 자세히 설명) : 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')
사용자가 입력 한 startDate 및 endDate 필드를 가져 오는 Javascript를 이미 구현하고 내 앱에서 다른 플라스크 경로를 "가져 오기"하여 내 데이터베이스에서 사용 된 모든 무선 네트워크 (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되기 전에 다음과 같습니다.
[{'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)
Javascript 가져 오기 호출에 응답 form.ssidFilter.choices
하는 동일한 getSSIDs
함수를 호출하여 동적 필드 를 채우고 있지만 datetime.now()
시작 날짜와 종료 날짜를 모두 전달하고 있습니다. 이것은 처음에 사용자에게 현재 사용중인 무선 네트워크 목록을 표시하기위한 것이지만 날짜를 변경하는 즉시 목록은 다른 네트워크 집합으로 업데이트됩니다.
여기에 문제가 있습니다. form.ssidFilter.choices
클라이언트가 보고서 날짜를 입력 한 후 돌아 오는 네트워크 목록을 포함하도록 허용 가능한 선택 목록 ( )을 어떻게 설정할 수 있습니까?
내가 탐색중인 가능한 솔루션 :
날짜 선택시 페이지를 다시로드하여 동적 데이터로 새 양식을 인스턴스화합니다.
처음에는 사용 가능한 모든 선택 항목의 방대한 목록을 유지하면 사용자가 양식의 날짜를 변경할 때 JS를 통해 선택 항목이 동적으로 필터링됩니다.
아, 그리고 선택한 SSID가 form.ssidFilter.choices = getSSIDs(datetime.now(), datetime.now())
명령문 의 목록에있는 SSID 인 경우 양식이 제대로 작동합니다 . 이 문제는 원래 선택 목록에없는 항목을 선택한 경우에만 발생합니다 (이치에 맞습니다-해결 방법을 모르겠습니다).
시간 내 주셔서 감사합니다.
@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
함수 에서 좀 더 철저한 유효성 검사를 수행 합니다.
경로가 GET 또는 POST 요청을 처리하는지 여부에 따라 양식을 다르게 인스턴스화 할 수 있습니다.
@app.route('/requestReport', methods=['GET', 'POST'])
def requestReport():
form = RequestReportForm()
if request.method == "GET":
start = end = datetime.now()
else:
# validate start and end dates here first?
start, end = form.startDate.data, form.endDate.data
form.ssidFilter.choices = getSSIDs(start, end)
...
... POST의 경우 유효성이 검사되기 전에 시작 및 종료 날짜를 사용합니다. 그래서 하나의 옵션은 인라인 (내가 코멘트를 넣어 한)은 "POST"조건 처리 내부 첫째 검증을하는 것입니다, 또는 다른이 무시하는 것입니다 .validate()
온 방법 RequestReportForm
.
이것은 다음의 독 스트링입니다 Form.validate()
.
"""
Validates the form by calling `validate` on each field.
:param extra_validators:
If provided, is a dict mapping field names to a sequence of
callables which will be passed as extra validators to the field's
`validate` method.
Returns `True` if no errors occur.
"""
가능한 구현은 다음과 같습니다.
class RequestReportForm(FlaskForm):
...
def validate(self, *args, **kwargs):
"""Ensure ssidFilter field choices match input startDate and endDate"""
if not (self.startDate.validate(self) and self.endDate.validate(self)):
return False
self.ssidFilter.choices = getSSIDs(self.startDate.data, self.endDate.data)
return super().validate(*args, **kwargs)
FlaskForm.validate_on_submit()
먼저 양식이 제출되었는지 확인한 다음 사용자 지정 .validate()
메서드를 호출합니다 . 이 방법은 먼저 시작 및 종료 날짜가 유효한지 확인하고이를 사용하여 ssidFilter
최종적으로 MRO를 백업하는 유효성 검사를 위임하기 전에 예상 가능한 값을 채 웁니다 .
이 코드를 실행하지 않았으므로 오류가 있으면 알려주십시오.하지만 적합한 경우 실행할 수있을만큼 충분히 아이디어를 얻었기를 바랍니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다