Python Flask WTForms : "유효하지 않은 선택"을 반환하는 동적 SelectField

David00

우선, 여기에 유사한 질문이 수십 개 있다는 것을 알고 있습니다. 나는 전부는 아니지만 대부분을 보았고 그들 중 어느 것도 나를 해결책으로 인도하지 못했습니다. 다음 질문은 가장 유사하지만 "동적"구현은 해당 질문과 약간 다릅니다 (아래에 자세히 설명) : 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함수 에서 좀 더 철저한 유효성 검사를 수행 합니다.

SuperShoot

경로가 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] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

SelectField : 왜 "유효하지 않은 선택 오류"를 반환합니까?

분류에서Dev

InvalidSelectorException : 메시지 : 유효하지 않은 선택자 : xpath 표현식의 결과는 [object Attr]입니다. XPath Selenium을 사용하는 요소 여야합니다.

분류에서Dev

유효하지 않은 선택적 속성 인 경우 JSON 스키마에서 유효성 검사 오류가 발생합니다.

분류에서Dev

해결됨 : selenium.common.exceptions.InvalidSelectorException : 메시지 : 유효하지 않은 선택기 : 유효하지 않거나 잘못된 선택기가 지정되었습니다

분류에서Dev

Flask / Python / WTForms 유효성 검사 및 동적으로 SelectField 선택 설정

분류에서Dev

wtforms SelectField는 항상 없음을 반환합니다.

분류에서Dev

동적 WTForms SelectField는 db에서 테이블의 열 제목을 보여줍니다.

분류에서Dev

Flask는 NaN을 반환하는 Integerfield ()를 wtforms

분류에서Dev

SelectField가 작동하지 않는 WTForms 게시물

분류에서Dev

AJAX로 채워진 FlaskForm (Flask-WTForms) SelectField 유효성 검사

분류에서Dev

How do I make my flask wtforms SelectField look like a dropdown?

분류에서Dev

WTForms가 SelectField 상자의 유효성을 검사하지 못하는 것 같습니다.

분류에서Dev

UnboundField를 반환하는 WTForms에 동적으로 필드 추가

분류에서Dev

Flask WTForms를 사용하여 다중 선택 옵션을 만드는 방법

분류에서Dev

flask-wtf wtforms에서 다양한 필드 유형을 결합하는 방법

분류에서Dev

Flask-WTForms : 동적으로 이름 및 ID 속성 생성

분류에서Dev

WTForms, 둘 이상의 SelectField가있는 양식? SelectFieldArray가 있습니까?

분류에서Dev

단일 앱 경로에서 여러 응답을 반환하는 방법 : Flask (Python)

분류에서Dev

SQL 쿼리로 WTForms SelectField 채우기

분류에서Dev

Flask WTForms에서 Javascript가있는 로더

분류에서Dev

Python Flask : 변환기는 어떻게 작동합니까? (동적 라우팅)

분류에서Dev

Flask 동적 경로가 작동하지 않음-Real Python

분류에서Dev

동일한 출력 Python을 반환하는 사전

분류에서Dev

Python 사전을 동적으로 빌드해도 원하는 결과가 반환되지 않음

분류에서Dev

동적 유형을 반환하는 목적 C 메서드

분류에서Dev

다음 양식 필드로 이동하기 위해 jQuery를 사용하는 Flask-WTForms

분류에서Dev

WTForms FormField의 기본값을 동적으로 설정하려면 어떻게해야합니까?

분류에서Dev

flask wtforms, what input is pressed

분류에서Dev

SQLAlchemy가있는 Flask WTForms : 데이터베이스에 양식을 저장할 때 UnmappedInstanceError

Related 관련 기사

  1. 1

    SelectField : 왜 "유효하지 않은 선택 오류"를 반환합니까?

  2. 2

    InvalidSelectorException : 메시지 : 유효하지 않은 선택자 : xpath 표현식의 결과는 [object Attr]입니다. XPath Selenium을 사용하는 요소 여야합니다.

  3. 3

    유효하지 않은 선택적 속성 인 경우 JSON 스키마에서 유효성 검사 오류가 발생합니다.

  4. 4

    해결됨 : selenium.common.exceptions.InvalidSelectorException : 메시지 : 유효하지 않은 선택기 : 유효하지 않거나 잘못된 선택기가 지정되었습니다

  5. 5

    Flask / Python / WTForms 유효성 검사 및 동적으로 SelectField 선택 설정

  6. 6

    wtforms SelectField는 항상 없음을 반환합니다.

  7. 7

    동적 WTForms SelectField는 db에서 테이블의 열 제목을 보여줍니다.

  8. 8

    Flask는 NaN을 반환하는 Integerfield ()를 wtforms

  9. 9

    SelectField가 작동하지 않는 WTForms 게시물

  10. 10

    AJAX로 채워진 FlaskForm (Flask-WTForms) SelectField 유효성 검사

  11. 11

    How do I make my flask wtforms SelectField look like a dropdown?

  12. 12

    WTForms가 SelectField 상자의 유효성을 검사하지 못하는 것 같습니다.

  13. 13

    UnboundField를 반환하는 WTForms에 동적으로 필드 추가

  14. 14

    Flask WTForms를 사용하여 다중 선택 옵션을 만드는 방법

  15. 15

    flask-wtf wtforms에서 다양한 필드 유형을 결합하는 방법

  16. 16

    Flask-WTForms : 동적으로 이름 및 ID 속성 생성

  17. 17

    WTForms, 둘 이상의 SelectField가있는 양식? SelectFieldArray가 있습니까?

  18. 18

    단일 앱 경로에서 여러 응답을 반환하는 방법 : Flask (Python)

  19. 19

    SQL 쿼리로 WTForms SelectField 채우기

  20. 20

    Flask WTForms에서 Javascript가있는 로더

  21. 21

    Python Flask : 변환기는 어떻게 작동합니까? (동적 라우팅)

  22. 22

    Flask 동적 경로가 작동하지 않음-Real Python

  23. 23

    동일한 출력 Python을 반환하는 사전

  24. 24

    Python 사전을 동적으로 빌드해도 원하는 결과가 반환되지 않음

  25. 25

    동적 유형을 반환하는 목적 C 메서드

  26. 26

    다음 양식 필드로 이동하기 위해 jQuery를 사용하는 Flask-WTForms

  27. 27

    WTForms FormField의 기본값을 동적으로 설정하려면 어떻게해야합니까?

  28. 28

    flask wtforms, what input is pressed

  29. 29

    SQLAlchemy가있는 Flask WTForms : 데이터베이스에 양식을 저장할 때 UnmappedInstanceError

뜨겁다태그

보관