code: def validate(self) -> None:
      # Validate/populate model exists
      self._models = ChartDAO.find_by_ids(self._model_ids)
      if not self._models or len(self._models) != len(self._model_ids):
          raise ChartNotFoundError()
      # Check there are no associated ReportSchedules
      if reports := ReportScheduleDAO.find_by_chart_ids(
          self._model_ids
      ):
          report_names = [report.name for report in reports]
          raise ChartDeleteFailedReportsExistError(
              _(
                  f"There are associated alerts or reports: {','.join(report_names)}"
              )
          )
      # Check ownership
      for model in self._models:
          try:
              security_manager.raise_for_ownership(model)
          except SupersetSecurityException as ex:
              raise ChartForbiddenError() from ex
  
file_path: superset/superset/commands/chart/delete.py
imports: import logging
  from typing import Optional
  from flask_babel import lazy_gettext
  from superset import security_manager
  from superset.commands.base import BaseCommand
  from superset.commands.chart.exceptions import ChartDeleteFailedError, ChartDeleteFailedReportsExistError, ChartForbiddenError, ChartNotFoundError
  from superset.daos.chart import ChartDAO
  from superset.daos.exceptions import DAODeleteFailedError
  from superset.daos.report import ReportScheduleDAO
  from superset.exceptions import SupersetSecurityException
  from superset.models.dashboard import Dashboard
  from superset.models.slice import Slice
label_desc: Use image node_id 3 for calling the DeleteChartCommand obj's underlying member method code with example usage: obj.validate() without return types