mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-05-13 01:33:16 +00:00
Added system check for ForeignKey cascade
Pages can be linked to other Pages, Images, etc through ForeignKeys. If the object being referenced by a page gets deleted, the page itself will be deleted as well. Also, the page will not be cleanly removed from the tree (leaving orphans, out of date num_child, etc). It is very common to accidentally forget to set the on_delete action to models.SET_NULL. This pull request checks all ForeignKey fields on pages and makes sure that they are not set to cascade. If they are set to cascade, the developer will be warned of their mistake. This only works for Django 1.7 users as it uses the system checks framework.
This commit is contained in:
parent
d770e94687
commit
bd36438545
1 changed files with 28 additions and 1 deletions
|
|
@ -26,6 +26,11 @@ from django.core.exceptions import ValidationError, ImproperlyConfigured
|
|||
from django.utils.functional import cached_property
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
try:
|
||||
from django.core import checks
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from treebeard.mp_tree import MP_Node
|
||||
|
||||
from wagtail.wagtailcore.utils import camelcase_to_underscore, resolve_model_string
|
||||
|
|
@ -260,7 +265,7 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed
|
|||
live = models.BooleanField(default=True, editable=False)
|
||||
has_unpublished_changes = models.BooleanField(default=False, editable=False)
|
||||
url_path = models.CharField(max_length=255, blank=True, editable=False)
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, editable=False, related_name='owned_pages')
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, editable=False, on_delete=models.SET_NULL, related_name='owned_pages')
|
||||
|
||||
seo_title = models.CharField(verbose_name=_("Page title"), max_length=255, blank=True, help_text=_("Optional. 'Search Engine Friendly' title. This will appear at the top of the browser window."))
|
||||
show_in_menus = models.BooleanField(default=False, help_text=_("Whether a link to this page will appear in automatically generated menus"))
|
||||
|
|
@ -343,6 +348,28 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed
|
|||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def check(cls, **kwargs):
|
||||
errors = super(Page, cls).check(**kwargs)
|
||||
|
||||
# Check that foreign keys from pages are not configured to cascade
|
||||
# This is the default Django behaviour which must be explicitly overridden
|
||||
# to prevent pages disappearing unexpectedly and the tree being corrupted
|
||||
|
||||
for field in cls._meta.fields:
|
||||
if isinstance(field, models.ForeignKey) and field.name not in ['page_ptr', 'content_type']:
|
||||
if field.rel.on_delete == models.CASCADE:
|
||||
errors.append(
|
||||
checks.Error(
|
||||
"Field hasn't specified on_delete action",
|
||||
hint="Set on_delete=models.SET_NULL and make sure the field is nullable.",
|
||||
obj=field,
|
||||
id='wagtailcore.E001',
|
||||
)
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
def _update_descendant_url_paths(self, old_url_path, new_url_path):
|
||||
cursor = connection.cursor()
|
||||
if connection.vendor == 'sqlite':
|
||||
|
|
|
|||
Loading…
Reference in a new issue