@@ -172,6 +172,7 @@ def __init__(self, **kwargs):
172172 if "request" in kwargs :
173173 self .setup (kwargs ["request" ])
174174
175+ self ._validate_called = False
175176 self .errors = {}
176177 self ._set_default_template_name ()
177178 self ._set_caches ()
@@ -358,6 +359,9 @@ def get_context_data(self, **kwargs):
358359
359360 return context
360361
362+ def is_valid (self , model_names : List = None ) -> bool :
363+ return len (self .validate (model_names ).keys ()) == 0
364+
361365 def validate (self , model_names : List = None ) -> Dict :
362366 """
363367 Validates the data using the `form_class` set on the component.
@@ -367,30 +371,35 @@ def validate(self, model_names: List = None) -> Dict:
367371 """
368372 # TODO: Handle form.non_field_errors()?
369373
374+ if self ._validate_called :
375+ return self .errors
376+
377+ self ._validate_called = True
378+
370379 data = self ._attributes ()
371380 form = self ._get_form (data )
372381
373382 if form :
374383 form_errors = form .errors .get_json_data (escape_html = True )
375384
376- if model_names is not None :
377- # This code is confusing, but handles this use-case:
378- # the component has two models, one that starts with an error and one
379- # that is valid. Validating the valid one should not show an error for
380- # the invalid one. Only after the invalid field is updated, should the
381- # error show up and persist, even after updating the valid form.
382- if self .errors :
383- keys_to_remove = []
384-
385- for key , value in self .errors .items ():
386- if key in form_errors :
387- self .errors [key ] = value
388- else :
389- keys_to_remove .append (key )
390-
391- for key in keys_to_remove :
392- self .errors .pop (key )
385+ # This code is confusing, but handles this use-case:
386+ # the component has two models, one that starts with an error and one
387+ # that is valid. Validating the valid one should not show an error for
388+ # the invalid one. Only after the invalid field is updated, should the
389+ # error show up and persist, even after updating the valid form.
390+ if self .errors :
391+ keys_to_remove = []
393392
393+ for key , value in self .errors .items ():
394+ if key in form_errors :
395+ self .errors [key ] = value
396+ else :
397+ keys_to_remove .append (key )
398+
399+ for key in keys_to_remove :
400+ self .errors .pop (key )
401+
402+ if model_names is not None :
394403 for key , value in form_errors .items ():
395404 if key in model_names :
396405 self .errors [key ] = value
@@ -514,6 +523,7 @@ def _is_public(self, name: str) -> bool:
514523 "calling" ,
515524 "called" ,
516525 "validate" ,
526+ "is_valid" ,
517527 "get_frontend_context_variables" ,
518528 "errors" ,
519529 "updated" ,
@@ -551,7 +561,9 @@ def create(
551561 key = f"{ component_name } -{ component_id } "
552562
553563 if key in constructed_views_cache :
554- return constructed_views_cache [key ]
564+ component = constructed_views_cache [key ]
565+ component ._validate_called = False
566+ return component
555567
556568 if component_name in views_cache :
557569 component = views_cache [component_name ](
@@ -582,6 +594,7 @@ def create(
582594 key = f"{ component_name } -{ component_id } "
583595 constructed_views_cache [key ] = component
584596
597+ component ._validate_called = False
585598 return component
586599
587600 locations = []
0 commit comments