Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent ForeignKeyViolation error on delete #23414

Merged
merged 3 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion superset/charts/commands/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
import logging
from typing import Optional
from typing import cast, Optional

from flask_appbuilder.models.sqla import Model
from flask_babel import lazy_gettext as _
Expand Down Expand Up @@ -45,8 +45,13 @@ def __init__(self, model_id: int):

def run(self) -> Model:
self.validate()
self._model = cast(Slice, self._model)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this necessary? The doc said This returns the value unchanged. but only good for type checker

Copy link
Member Author

@betodealmeida betodealmeida Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's needed to make the type checker happy.

On __init__ self._model will be set to None. When we call self.validate() it will either set self._model to a Slice or raise an exception, so here we're telling the type checker that we know self._model is of type Slice.

try:
Dashboard.clear_cache_for_slice(slice_id=self._model_id)
# Even though SQLAlchemy should in theory delete rows from the association
# table, sporadically Superset will error because the rows are not deleted.
# Let's do it manually here to prevent the error.
self._model.owners = []
chart = ChartDAO.delete(self._model)
except DAODeleteFailedError as ex:
logger.exception(ex.exception)
Expand Down
7 changes: 6 additions & 1 deletion superset/datasets/commands/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
import logging
from typing import Optional
from typing import cast, Optional

from flask_appbuilder.models.sqla import Model
from sqlalchemy.exc import SQLAlchemyError
Expand Down Expand Up @@ -43,7 +43,12 @@ def __init__(self, model_id: int):

def run(self) -> Model:
self.validate()
self._model = cast(SqlaTable, self._model)
try:
# Even though SQLAlchemy should in theory delete rows from the association
# table, sporadically Superset will error because the rows are not deleted.
# Let's do it manually here to prevent the error.
self._model.owners = []
dataset = DatasetDAO.delete(self._model, commit=False)
db.session.commit()
except (SQLAlchemyError, DAODeleteFailedError) as ex:
Expand Down
Loading