From c2e70f02653519db3a49cd48f5158ccad7434d25 Mon Sep 17 00:00:00 2001 From: Flavio Curella Date: Wed, 22 Jul 2015 09:43:21 -0500 Subject: [PATCH] Fixed #21127 -- Started deprecation toward requiring on_delete for ForeignKey/OneToOneField --- .../contrib/admin/migrations/0001_initial.py | 14 +- django/contrib/admin/models.py | 13 +- .../contrib/auth/migrations/0001_initial.py | 7 +- django/contrib/auth/models.py | 6 +- django/contrib/contenttypes/fields.py | 1 + .../redirects/migrations/0001_initial.py | 7 +- django/contrib/redirects/models.py | 2 +- django/core/management/commands/inspectdb.py | 4 + django/db/models/base.py | 11 +- django/db/models/fields/related.py | 68 +++++- docs/internals/deprecation.txt | 3 + docs/intro/overview.txt | 4 +- docs/intro/tutorial02.txt | 2 +- docs/ref/contrib/admin/admindocs.txt | 8 +- docs/ref/contrib/admin/index.txt | 12 +- docs/ref/contrib/contenttypes.txt | 2 +- docs/ref/contrib/gis/model-api.txt | 2 +- docs/ref/contrib/sites.txt | 6 +- docs/ref/models/database-functions.txt | 2 +- docs/ref/models/fields.txt | 217 +++++++++++------- docs/ref/models/options.txt | 2 +- docs/ref/models/querysets.txt | 15 +- docs/ref/models/relations.txt | 2 +- docs/releases/1.9.txt | 13 ++ docs/topics/auth/customizing.txt | 7 +- .../class-based-views/generic-display.txt | 2 +- .../class-based-views/generic-editing.txt | 2 +- docs/topics/db/examples/many_to_one.txt | 2 +- docs/topics/db/examples/one_to_one.txt | 8 +- docs/topics/db/managers.txt | 2 +- docs/topics/db/models.txt | 32 ++- docs/topics/db/queries.txt | 6 +- docs/topics/forms/modelforms.txt | 14 +- docs/topics/i18n/translation.txt | 16 +- docs/topics/serialization.txt | 4 +- tests/admin_changelist/models.py | 14 +- tests/admin_checks/models.py | 14 +- tests/admin_docs/models.py | 4 +- tests/admin_filters/models.py | 12 +- tests/admin_inlines/models.py | 50 ++-- tests/admin_ordering/models.py | 2 +- tests/admin_scripts/app_with_import/models.py | 2 +- tests/admin_utils/models.py | 17 +- tests/admin_views/models.py | 124 ++++++---- tests/admin_widgets/models.py | 23 +- tests/aggregation/models.py | 4 +- tests/aggregation_regress/models.py | 14 +- tests/annotations/models.py | 6 +- tests/app_loading/not_installed/models.py | 2 +- tests/auth_tests/models/with_foreign_key.py | 6 +- tests/backends/models.py | 14 +- tests/basic/models.py | 8 +- tests/check_framework/tests.py | 8 +- tests/contenttypes_tests/models.py | 2 +- tests/contenttypes_tests/tests.py | 22 +- tests/custom_columns/models.py | 8 +- tests/custom_managers/models.py | 17 +- tests/custom_pk/models.py | 2 +- tests/dates/models.py | 2 +- tests/datetimes/models.py | 2 +- tests/db_functions/models.py | 2 +- tests/defer/models.py | 2 +- tests/defer_regress/models.py | 20 +- tests/delete/models.py | 50 ++-- tests/delete_regress/models.py | 30 +-- tests/distinct_on_fields/models.py | 22 +- tests/expressions/models.py | 2 + tests/expressions_case/models.py | 6 +- tests/extra_regress/models.py | 4 +- tests/field_deconstruction/tests.py | 28 +-- tests/fixtures/models.py | 6 +- tests/fixtures_regress/models.py | 28 +-- tests/foreign_object/models.py | 37 ++- tests/forms_tests/models.py | 2 + tests/forms_tests/tests/tests.py | 4 +- tests/generic_inline_admin/models.py | 6 +- tests/generic_relations/models.py | 12 +- tests/generic_relations_regress/models.py | 22 +- tests/get_or_create/models.py | 9 +- tests/gis_tests/geoapp/models.py | 2 +- .../gis_migrations/migrations/0001_initial.py | 9 +- tests/gis_tests/layermap/models.py | 2 +- tests/gis_tests/relatedapp/models.py | 10 +- tests/indexes/models.py | 8 +- tests/inline_formsets/models.py | 8 +- tests/inspectdb/models.py | 8 +- tests/inspectdb/tests.py | 26 ++- tests/introspection/models.py | 4 +- tests/invalid_models_tests/test_models.py | 28 ++- .../test_relative_fields.py | 211 ++++++++++++----- tests/known_related_objects/models.py | 6 +- tests/lookup/models.py | 4 +- tests/m2m_and_m2o/models.py | 2 +- tests/m2m_intermediary/models.py | 4 +- tests/m2m_through/models.py | 39 ++-- tests/m2m_through_regress/models.py | 16 +- tests/m2o_recursive/models.py | 8 +- tests/managers_regress/models.py | 4 +- tests/many_to_one/models.py | 20 +- tests/many_to_one/tests.py | 4 +- tests/many_to_one_null/models.py | 4 +- .../book_app/migrations/0001_initial.py | 2 +- .../lookuperror_a/migrations/0003_a3.py | 4 +- .../lookuperror_a/models.py | 4 +- .../lookuperror_b/migrations/0002_b2.py | 2 +- .../lookuperror_b/models.py | 2 +- .../lookuperror_c/migrations/0002_c2.py | 2 +- .../lookuperror_c/models.py | 2 +- .../unmigrated_app/models.py | 2 +- tests/migrations/test_autodetector.py | 70 +++--- .../migrations/test_migrations/0002_second.py | 2 +- .../test_migrations_conflict/0002_second.py | 2 +- .../0001_initial.py | 2 +- .../0002_second.py | 2 +- .../test_migrations_first/second.py | 2 +- .../0002_conflicting_second.py | 2 +- .../0002_second.py | 2 +- .../test_migrations_no_changes/0002_second.py | 2 +- .../test_migrations_run_before/0002_second.py | 2 +- .../0001_squashed_0002.py | 2 +- .../test_migrations_squashed/0002_second.py | 2 +- .../test_migrations_unmigdep/0001_initial.py | 2 +- tests/migrations/test_operations.py | 22 +- tests/migrations/test_optimizer.py | 8 +- tests/migrations/test_state.py | 71 ++++-- tests/model_fields/models.py | 16 +- tests/model_fields/tests.py | 6 +- tests/model_forms/models.py | 25 +- tests/model_formsets/models.py | 34 +-- tests/model_formsets_regress/models.py | 10 +- tests/model_inheritance/models.py | 10 +- tests/model_inheritance_regress/models.py | 14 +- tests/model_meta/models.py | 31 +-- .../models/default_related_name.py | 6 +- tests/model_regress/models.py | 6 +- tests/model_validation/models.py | 4 +- tests/modeladmin/models.py | 8 +- tests/multiple_database/models.py | 8 +- tests/mutually_referential/models.py | 4 +- tests/nested_foreign_keys/models.py | 10 +- tests/null_fk/models.py | 12 +- tests/null_fk_ordering/models.py | 8 +- tests/null_queries/models.py | 6 +- tests/one_to_one/models.py | 22 +- tests/one_to_one/tests.py | 2 +- tests/order_with_respect_to/models.py | 4 +- tests/order_with_respect_to/tests.py | 2 +- tests/ordering/models.py | 6 +- .../migrations/0002_create_test_models.py | 12 +- tests/postgres_tests/models.py | 4 +- tests/prefetch_related/models.py | 55 +++-- tests/proxy_models/models.py | 10 +- tests/queries/models.py | 132 +++++------ tests/queryset_pickle/models.py | 2 +- tests/raw_query/models.py | 4 +- tests/reverse_lookup/models.py | 6 +- tests/schema/models.py | 13 +- tests/schema/tests.py | 37 +-- tests/select_related/models.py | 20 +- tests/select_related_onetoone/models.py | 12 +- tests/select_related_regress/models.py | 45 ++-- tests/serializers/models.py | 8 +- tests/serializers_regress/models.py | 22 +- .../migrations/0001_initial.py | 6 +- tests/sites_framework/models.py | 4 +- tests/sites_framework/tests.py | 2 +- tests/string_lookup/models.py | 8 +- tests/syndication_tests/models.py | 2 +- tests/test_utils/models.py | 4 +- tests/timezones/models.py | 2 +- tests/unmanaged_models/models.py | 8 +- tests/update/models.py | 8 +- tests/update_only_fields/models.py | 2 +- tests/utils_tests/models.py | 2 +- tests/validation/models.py | 16 +- tests/view_tests/models.py | 2 +- 176 files changed, 1525 insertions(+), 1008 deletions(-) diff --git a/django/contrib/admin/migrations/0001_initial.py b/django/contrib/admin/migrations/0001_initial.py index 0360f59269..c615bd79c3 100644 --- a/django/contrib/admin/migrations/0001_initial.py +++ b/django/contrib/admin/migrations/0001_initial.py @@ -23,8 +23,18 @@ class Migration(migrations.Migration): ('object_repr', models.CharField(max_length=200, verbose_name='object repr')), ('action_flag', models.PositiveSmallIntegerField(verbose_name='action flag')), ('change_message', models.TextField(verbose_name='change message', blank=True)), - ('content_type', models.ForeignKey(to_field='id', blank=True, to='contenttypes.ContentType', null=True, verbose_name='content type')), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='user')), + ('content_type', models.ForeignKey( + to_field='id', + on_delete=models.SET_NULL, + blank=True, null=True, + to='contenttypes.ContentType', + verbose_name='content type', + )), + ('user', models.ForeignKey( + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name='user', + )), ], options={ 'ordering': ('-action_time',), diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index 65c18d99af..f51a015935 100644 --- a/django/contrib/admin/models.py +++ b/django/contrib/admin/models.py @@ -27,8 +27,17 @@ class LogEntryManager(models.Manager): @python_2_unicode_compatible class LogEntry(models.Model): action_time = models.DateTimeField(_('action time'), auto_now=True) - user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user')) - content_type = models.ForeignKey(ContentType, verbose_name=_('content type'), blank=True, null=True) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + models.CASCADE, + verbose_name=_('user'), + ) + content_type = models.ForeignKey( + ContentType, + models.SET_NULL, + verbose_name=_('content type'), + blank=True, null=True, + ) object_id = models.TextField(_('object id'), blank=True, null=True) object_repr = models.CharField(_('object repr'), max_length=200) action_flag = models.PositiveSmallIntegerField(_('action flag')) diff --git a/django/contrib/auth/migrations/0001_initial.py b/django/contrib/auth/migrations/0001_initial.py index 2c2960f6be..fcc9d05318 100644 --- a/django/contrib/auth/migrations/0001_initial.py +++ b/django/contrib/auth/migrations/0001_initial.py @@ -19,7 +19,12 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=50, verbose_name='name')), - ('content_type', models.ForeignKey(to='contenttypes.ContentType', to_field='id', verbose_name='content type')), + ('content_type', models.ForeignKey( + to='contenttypes.ContentType', + on_delete=models.CASCADE, + to_field='id', + verbose_name='content type', + )), ('codename', models.CharField(max_length=100, verbose_name='codename')), ], options={ diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index febadfc1be..070d7d4435 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -59,7 +59,11 @@ class Permission(models.Model): created for each Django model. """ name = models.CharField(_('name'), max_length=255) - content_type = models.ForeignKey(ContentType, verbose_name=_('content type')) + content_type = models.ForeignKey( + ContentType, + models.CASCADE, + verbose_name=_('content type'), + ) codename = models.CharField(_('codename'), max_length=100) objects = PermissionManager() diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index f5c1804a35..6548c39b4b 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -303,6 +303,7 @@ class GenericRelation(ForeignObject): ) kwargs['blank'] = True + kwargs['on_delete'] = models.CASCADE kwargs['editable'] = False kwargs['serialize'] = False diff --git a/django/contrib/redirects/migrations/0001_initial.py b/django/contrib/redirects/migrations/0001_initial.py index 8d4da06d26..cfd5dcf5a3 100644 --- a/django/contrib/redirects/migrations/0001_initial.py +++ b/django/contrib/redirects/migrations/0001_initial.py @@ -15,7 +15,12 @@ class Migration(migrations.Migration): name='Redirect', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('site', models.ForeignKey(to='sites.Site', to_field='id', verbose_name='site')), + ('site', models.ForeignKey( + to='sites.Site', + to_field='id', + on_delete=models.CASCADE, + verbose_name='site', + )), ('old_path', models.CharField(help_text="This should be an absolute path, excluding the domain name. Example: '/events/search/'.", max_length=200, verbose_name='redirect from', db_index=True)), ('new_path', models.CharField(help_text="This can be either an absolute path (as above) or a full URL starting with 'http://'.", max_length=200, verbose_name='redirect to', blank=True)), ], diff --git a/django/contrib/redirects/models.py b/django/contrib/redirects/models.py index 254f66b478..41260a54d1 100644 --- a/django/contrib/redirects/models.py +++ b/django/contrib/redirects/models.py @@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _ @python_2_unicode_compatible class Redirect(models.Model): - site = models.ForeignKey(Site, verbose_name=_('site')) + site = models.ForeignKey(Site, models.CASCADE, verbose_name=_('site')) old_path = models.CharField(_('redirect from'), max_length=200, db_index=True, help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) new_path = models.CharField(_('redirect to'), max_length=200, blank=True, diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py index 40bfffe5d0..3e0a9e5df3 100644 --- a/django/core/management/commands/inspectdb.py +++ b/django/core/management/commands/inspectdb.py @@ -40,6 +40,7 @@ class Command(BaseCommand): yield "# You'll have to do the following manually to clean this up:" yield "# * Rearrange models' order" yield "# * Make sure each model has one field with primary_key=True" + yield "# * Make sure each ForeignKey has `on_delete` set to the desidered behavior." yield ( "# * Remove `managed = False` lines if you wish to allow " "Django to create, modify, and delete the table" @@ -128,6 +129,9 @@ class Command(BaseCommand): '' if '.' in field_type else 'models.', field_type, ) + if field_type.startswith('ForeignKey('): + field_desc += ', models.DO_NOTHING' + if extra_params: if not field_desc.endswith('('): field_desc += ', ' diff --git a/django/db/models/base.py b/django/db/models/base.py index b679d08654..2a8e5fd2c8 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -18,7 +18,7 @@ from django.db import ( ) from django.db.models import signals from django.db.models.constants import LOOKUP_SEP -from django.db.models.deletion import Collector +from django.db.models.deletion import CASCADE, Collector from django.db.models.fields import AutoField from django.db.models.fields.related import ( ForeignObjectRel, ManyToOneRel, OneToOneField, lazy_related_operation, @@ -230,8 +230,13 @@ class ModelBase(type): field = parent_links[base_key] elif not is_proxy: attr_name = '%s_ptr' % base._meta.model_name - field = OneToOneField(base, name=attr_name, - auto_created=True, parent_link=True) + field = OneToOneField( + base, + on_delete=CASCADE, + name=attr_name, + auto_created=True, + parent_link=True, + ) # Only add the ptr field if it's not already present; # e.g. migrations will already have it specified if not hasattr(new_class, attr_name): diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index b038fdf116..c10b2658b5 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -30,6 +30,7 @@ from django.utils.deprecation import ( from django.utils.encoding import force_text, smart_text from django.utils.functional import cached_property, curry from django.utils.translation import ugettext_lazy as _ +from django.utils.version import get_docs_version RECURSIVE_RELATIONSHIP_CONSTANT = 'self' @@ -1584,9 +1585,10 @@ class ForeignObject(RelatedField): related_accessor_class = ForeignRelatedObjectsDescriptor rel_class = ForeignObjectRel - def __init__(self, to, from_fields, to_fields, rel=None, related_name=None, + def __init__(self, to, on_delete, from_fields, to_fields, rel=None, related_name=None, related_query_name=None, limit_choices_to=None, parent_link=False, - on_delete=CASCADE, swappable=True, **kwargs): + swappable=True, **kwargs): + if rel is None: rel = self.rel_class( self, to, @@ -1650,14 +1652,14 @@ class ForeignObject(RelatedField): def deconstruct(self): name, path, args, kwargs = super(ForeignObject, self).deconstruct() + kwargs['on_delete'] = self.remote_field.on_delete kwargs['from_fields'] = self.from_fields kwargs['to_fields'] = self.to_fields + if self.remote_field.related_name is not None: kwargs['related_name'] = self.remote_field.related_name if self.remote_field.related_query_name is not None: kwargs['related_query_name'] = self.remote_field.related_query_name - if self.remote_field.on_delete != CASCADE: - kwargs['on_delete'] = self.remote_field.on_delete if self.remote_field.parent_link: kwargs['parent_link'] = self.remote_field.parent_link # Work out string form of "to" @@ -1866,8 +1868,8 @@ class ForeignKey(ForeignObject): } description = _("Foreign Key (type determined by related field)") - def __init__(self, to, to_field=None, related_name=None, related_query_name=None, - limit_choices_to=None, parent_link=False, on_delete=CASCADE, + def __init__(self, to, on_delete=None, related_name=None, related_query_name=None, + limit_choices_to=None, parent_link=False, to_field=None, db_constraint=True, **kwargs): try: to._meta.model_name @@ -1885,6 +1887,28 @@ class ForeignKey(ForeignObject): # be correct until contribute_to_class is called. Refs #12190. to_field = to_field or (to._meta.pk and to._meta.pk.name) + if on_delete is None: + warnings.warn( + "on_delete will be a required arg for %s in Django 2.0. " + "Set it to models.CASCADE if you want to maintain the current default behavior. " + "See https://docs.djangoproject.com/en/%s/ref/models/fields/" + "#django.db.models.ForeignKey.on_delete" % ( + self.__class__.__name__, + get_docs_version(), + ), + RemovedInDjango20Warning, 2) + on_delete = CASCADE + + elif not callable(on_delete): + warnings.warn( + "The signature for {0} will change in Django 2.0. " + "Pass to_field='{1}' as a kwarg instead of as an arg.".format( + self.__class__.__name__, + on_delete, + ), + RemovedInDjango20Warning, 2) + on_delete, to_field = to_field, on_delete + kwargs['rel'] = self.rel_class( self, to, to_field, related_name=related_name, @@ -1897,7 +1921,7 @@ class ForeignKey(ForeignObject): kwargs['db_index'] = kwargs.get('db_index', True) super(ForeignKey, self).__init__( - to, from_fields=['self'], to_fields=[to_field], **kwargs) + to, on_delete, from_fields=['self'], to_fields=[to_field], **kwargs) self.db_constraint = db_constraint @@ -2101,9 +2125,33 @@ class OneToOneField(ForeignKey): description = _("One-to-one relationship") - def __init__(self, to, to_field=None, **kwargs): + def __init__(self, to, on_delete=None, to_field=None, **kwargs): kwargs['unique'] = True - super(OneToOneField, self).__init__(to, to_field, **kwargs) + + if on_delete is None: + warnings.warn( + "on_delete will be a required arg for %s in Django 2.0. " + "Set it to models.CASCADE if you want to maintain the current default behavior. " + "See https://docs.djangoproject.com/en/%s/ref/models/fields/" + "#django.db.models.ForeignKey.on_delete" % ( + self.__class__.__name__, + get_docs_version(), + ), + RemovedInDjango20Warning, 2) + on_delete = CASCADE + + elif not callable(on_delete): + warnings.warn( + "The signature for {0} will change in Django 2.0. " + "Pass to_field='{1}' as a kwarg instead of as an arg.".format( + self.__class__.__name__, + on_delete, + ), + RemovedInDjango20Warning, 2) + to_field = on_delete + on_delete = CASCADE # Avoid warning in superclass + + super(OneToOneField, self).__init__(to, on_delete, to_field=to_field, **kwargs) def deconstruct(self): name, path, args, kwargs = super(OneToOneField, self).deconstruct() @@ -2162,12 +2210,14 @@ def create_many_to_many_intermediary_model(field, klass): related_name='%s+' % name, db_tablespace=field.db_tablespace, db_constraint=field.remote_field.db_constraint, + on_delete=CASCADE, ), to: models.ForeignKey( to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace, db_constraint=field.remote_field.db_constraint, + on_delete=CASCADE, ) }) diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index ae57f5e8f4..a9e60b379f 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -30,6 +30,9 @@ details on these changes. * ``Field.remote_field.to`` attribute will be removed. +* The ``on_delete`` argument for ``ForeignKey`` and ``OneToOneField`` will be + required. + * ``django.db.models.fields.add_lazy_relation()`` will be removed. * When time zone support is enabled, database backends that don't support time diff --git a/docs/intro/overview.txt b/docs/intro/overview.txt index e9f574a4f5..8cb5651385 100644 --- a/docs/intro/overview.txt +++ b/docs/intro/overview.txt @@ -40,7 +40,7 @@ database-schema problems. Here's a quick example: pub_date = models.DateField() headline = models.CharField(max_length=200) content = models.TextField() - reporter = models.ForeignKey(Reporter) + reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) def __str__(self): # __unicode__ on Python 2 return self.headline @@ -154,7 +154,7 @@ as easy as registering your model in the admin site: pub_date = models.DateField() headline = models.CharField(max_length=200) content = models.TextField() - reporter = models.ForeignKey(Reporter) + reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) .. snippet:: :filename: mysite/news/admin.py diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt index 8fef748a88..e1dd7d0bc7 100644 --- a/docs/intro/tutorial02.txt +++ b/docs/intro/tutorial02.txt @@ -141,7 +141,7 @@ These concepts are represented by simple Python classes. Edit the class Choice(models.Model): - question = models.ForeignKey(Question) + question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt index 76060ae28e..09837a3550 100644 --- a/docs/ref/contrib/admin/admindocs.txt +++ b/docs/ref/contrib/admin/admindocs.txt @@ -74,8 +74,12 @@ A model with useful documentation might look like this:: """ slug = models.SlugField(help_text="A short label, generally used in URLs.") - author = models.ForeignKey(User) - blog = models.ForeignKey(Blog) + author = models.ForeignKey( + User, + models.SET_NULL, + blank=True, null=True, + ) + blog = models.ForeignKey(Blog, models.CASCADE) ... def publish(self): diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 6ade38064c..5e1d37b453 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -1957,7 +1957,7 @@ information. name = models.CharField(max_length=100) class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, on_delete=models.CASCADE) title = models.CharField(max_length=100) You can edit the books authored by an author on the author page. You add @@ -2174,8 +2174,8 @@ Take this model for instance:: from django.db import models class Friendship(models.Model): - to_person = models.ForeignKey(Person, related_name="friends") - from_person = models.ForeignKey(Person, related_name="from_friends") + to_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="friends") + from_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="from_friends") If you wanted to display an inline on the ``Person`` admin add/change pages you need to explicitly define the foreign key since it is unable to do so @@ -2281,8 +2281,8 @@ models:: members = models.ManyToManyField(Person, through='Membership') class Membership(models.Model): - person = models.ForeignKey(Person) - group = models.ForeignKey(Group) + person = models.ForeignKey(Person, on_delete=models.CASCADE) + group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64) @@ -2326,7 +2326,7 @@ you have the following models:: class Image(models.Model): image = models.ImageField(upload_to="images") - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 431c3094f1..8173f876c5 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -256,7 +256,7 @@ A simple example is a tagging system, which might look like this:: class TaggedItem(models.Model): tag = models.SlugField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') diff --git a/docs/ref/contrib/gis/model-api.txt b/docs/ref/contrib/gis/model-api.txt index 8f386ef284..04669a91b8 100644 --- a/docs/ref/contrib/gis/model-api.txt +++ b/docs/ref/contrib/gis/model-api.txt @@ -269,7 +269,7 @@ model:: street = models.CharField(max_length=100) city = models.CharField(max_length=100) state = models.CharField(max_length=2) - zipcode = models.ForeignKey(Zipcode) + zipcode = models.ForeignKey(Zipcode, on_delete=models.CASCADE) objects = models.GeoManager() The geographic manager is needed to do spatial queries on related ``Zipcode`` objects, diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt index c91c112f64..c127fa41f1 100644 --- a/docs/ref/contrib/sites.txt +++ b/docs/ref/contrib/sites.txt @@ -117,7 +117,7 @@ like this:: class Article(models.Model): headline = models.CharField(max_length=200) # ... - site = models.ForeignKey(Site) + site = models.ForeignKey(Site, on_delete=models.CASCADE) This has the same benefits as described in the last section. @@ -334,7 +334,7 @@ your model explicitly. For example:: photo = models.FileField(upload_to='/home/photos') photographer_name = models.CharField(max_length=100) pub_date = models.DateField() - site = models.ForeignKey(Site) + site = models.ForeignKey(Site, on_delete=models.CASCADE) objects = models.Manager() on_site = CurrentSiteManager() @@ -371,7 +371,7 @@ demonstrates this:: photo = models.FileField(upload_to='/home/photos') photographer_name = models.CharField(max_length=100) pub_date = models.DateField() - publish_on = models.ForeignKey(Site) + publish_on = models.ForeignKey(Site, on_delete=models.CASCADE) objects = models.Manager() on_site = CurrentSiteManager('publish_on') diff --git a/docs/ref/models/database-functions.txt b/docs/ref/models/database-functions.txt index 336e4afc05..51a2e4b998 100644 --- a/docs/ref/models/database-functions.txt +++ b/docs/ref/models/database-functions.txt @@ -113,7 +113,7 @@ Usage example:: class Comment(models.Model): body = models.TextField() modified = models.DateTimeField(auto_now=True) - blog = models.ForeignKey(Blog) + blog = models.ForeignKey(Blog, on_delete=models.CASCADE) >>> from django.db.models.functions import Greatest >>> blog = Blog.objects.create(body='Greatest is the best.') diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 0921fda6d8..f68223a82c 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -1116,15 +1116,22 @@ Django also defines a set of fields that represent relations. ``ForeignKey`` -------------- -.. class:: ForeignKey(othermodel, **options) +.. class:: ForeignKey(othermodel, on_delete, **options) A many-to-one relationship. Requires a positional argument: the class to which the model is related. +.. versionchanged:: 1.9 + + ``on_delete`` can now be used as the second positional argument (previously + it was typically only passed as a keyword argument). It will be a required + argument in Django 2.0. + .. _recursive-relationships: To create a recursive relationship -- an object that has a many-to-one -relationship with itself -- use ``models.ForeignKey('self')``. +relationship with itself -- use ``models.ForeignKey('self', +on_delete=models.CASCADE)``. .. _lazy-relationships: @@ -1134,7 +1141,10 @@ you can use the name of the model, rather than the model object itself:: from django.db import models class Car(models.Model): - manufacturer = models.ForeignKey('Manufacturer') + manufacturer = models.ForeignKey( + 'Manufacturer', + on_delete=models.CASCADE, + ) # ... class Manufacturer(models.Model): @@ -1147,7 +1157,10 @@ model above is defined in another application called ``production``, you'd need to use:: class Car(models.Model): - manufacturer = models.ForeignKey('production.Manufacturer') + manufacturer = models.ForeignKey( + 'production.Manufacturer', + on_delete=models.CASCADE, + ) This sort of reference can be useful when resolving circular import dependencies between two applications. @@ -1173,8 +1186,79 @@ deal with the field names of your model object. Arguments ~~~~~~~~~ -:class:`ForeignKey` accepts an extra set of arguments -- all optional -- that -define the details of how the relation works. +:class:`ForeignKey` accepts other arguments that define the details of how the +relation works. + +.. attribute:: ForeignKey.on_delete + + When an object referenced by a :class:`ForeignKey` is deleted, Django will + emulate the behavior of the SQL constraint specified by the + :attr:`on_delete` argument. For example, if you have a nullable + :class:`ForeignKey` and you want it to be set null when the referenced + object is deleted:: + + user = models.ForeignKey( + User, + models.SET_NULL, + blank=True, + null=True, + ) + + .. deprecated:: 1.9 + + :attr:`~ForeignKey.on_delete` will become a required argument in Django + 2.0. In older versions it defaults to ``CASCADE``. + +The possible values for :attr:`~ForeignKey.on_delete` are found in +:mod:`django.db.models`: + +* .. attribute:: CASCADE + + Cascade deletes. Django emulates the behavior of the SQL constraint ON + DELETE CASCADE and also deletes the object containing the ForeignKey. + +* .. attribute:: PROTECT + + Prevent deletion of the referenced object by raising + :exc:`~django.db.models.ProtectedError`, a subclass of + :exc:`django.db.IntegrityError`. + +* .. attribute:: SET_NULL + + Set the :class:`ForeignKey` null; this is only possible if + :attr:`~Field.null` is ``True``. + +* .. attribute:: SET_DEFAULT + + Set the :class:`ForeignKey` to its default value; a default for the + :class:`ForeignKey` must be set. + +* .. function:: SET() + + Set the :class:`ForeignKey` to the value passed to + :func:`~django.db.models.SET()`, or if a callable is passed in, + the result of calling it. In most cases, passing a callable will be + necessary to avoid executing queries at the time your models.py is + imported:: + + from django.conf import settings + from django.contrib.auth import get_user_model + from django.db import models + + def get_sentinel_user(): + return get_user_model().objects.get_or_create(username='deleted')[0] + + class MyModel(models.Model): + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.SET(get_sentinel_user), + ) + +* .. attribute:: DO_NOTHING + + Take no action. If your database backend enforces referential + integrity, this will cause an :exc:`~django.db.IntegrityError` unless + you manually add an SQL ``ON DELETE`` constraint to the database field. .. attribute:: ForeignKey.limit_choices_to @@ -1186,7 +1270,11 @@ define the details of how the relation works. For example:: - staff_member = models.ForeignKey(User, limit_choices_to={'is_staff': True}) + staff_member = models.ForeignKey( + User, + on_delete=models.CASCADE, + limit_choices_to={'is_staff': True}, + ) causes the corresponding field on the ``ModelForm`` to list only ``Users`` that have ``is_staff=True``. This may be helpful in the Django admin. @@ -1231,7 +1319,11 @@ define the details of how the relation works. ensure that the ``User`` model won't have a backwards relation to this model:: - user = models.ForeignKey(User, related_name='+') + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name='+', + ) .. attribute:: ForeignKey.related_query_name @@ -1241,7 +1333,12 @@ define the details of how the relation works. # Declare the ForeignKey with related_query_name class Tag(models.Model): - article = models.ForeignKey(Article, related_name="tags", related_query_name="tag") + article = models.ForeignKey( + Article, + on_delete=models.CASCADE, + related_name="tags", + related_query_name="tag", + ) name = models.CharField(max_length=255) # That's now the name of the reverse filter @@ -1265,65 +1362,6 @@ define the details of how the relation works. If this is set to ``False``, accessing a related object that doesn't exist will raise its ``DoesNotExist`` exception. -.. attribute:: ForeignKey.on_delete - - When an object referenced by a :class:`ForeignKey` is deleted, Django by - default emulates the behavior of the SQL constraint ``ON DELETE CASCADE`` - and also deletes the object containing the ``ForeignKey``. This behavior - can be overridden by specifying the :attr:`on_delete` argument. For - example, if you have a nullable :class:`ForeignKey` and you want it to be - set null when the referenced object is deleted:: - - user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL) - -The possible values for :attr:`~ForeignKey.on_delete` are found in -:mod:`django.db.models`: - -* .. attribute:: CASCADE - - Cascade deletes; the default. - -* .. attribute:: PROTECT - - Prevent deletion of the referenced object by raising - :exc:`~django.db.models.ProtectedError`, a subclass of - :exc:`django.db.IntegrityError`. - -* .. attribute:: SET_NULL - - Set the :class:`ForeignKey` null; this is only possible if - :attr:`~Field.null` is ``True``. - -* .. attribute:: SET_DEFAULT - - Set the :class:`ForeignKey` to its default value; a default for the - :class:`ForeignKey` must be set. - -* .. function:: SET() - - Set the :class:`ForeignKey` to the value passed to - :func:`~django.db.models.SET()`, or if a callable is passed in, - the result of calling it. In most cases, passing a callable will be - necessary to avoid executing queries at the time your models.py is - imported:: - - from django.conf import settings - from django.contrib.auth import get_user_model - from django.db import models - - def get_sentinel_user(): - return get_user_model().objects.get_or_create(username='deleted')[0] - - class MyModel(models.Model): - user = models.ForeignKey(settings.AUTH_USER_MODEL, - on_delete=models.SET(get_sentinel_user)) - -* .. attribute:: DO_NOTHING - - Take no action. If your database backend enforces referential - integrity, this will cause an :exc:`~django.db.IntegrityError` unless - you manually add an SQL ``ON DELETE`` constraint to the database field. - .. attribute:: ForeignKey.swappable Controls the migration framework's reaction if this :class:`ForeignKey` @@ -1367,7 +1405,7 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in allow_unsaved_instance_assignment = True class Book(models.Model): - author = UnsavedForeignKey(Author) + author = UnsavedForeignKey(Author, on_delete=models.CASCADE) .. _ref-manytomany: @@ -1492,12 +1530,20 @@ that control how the relationship functions. class Group(models.Model): name = models.CharField(max_length=128) - members = models.ManyToManyField(Person, through='Membership', through_fields=('group', 'person')) + members = models.ManyToManyField( + Person, + through='Membership', + through_fields=('group', 'person'), + ) class Membership(models.Model): - group = models.ForeignKey(Group) - person = models.ForeignKey(Person) - inviter = models.ForeignKey(Person, related_name="membership_invites") + group = models.ForeignKey(Group, on_delete=models.CASCADE) + person = models.ForeignKey(Person, on_delete=models.CASCADE) + inviter = models.ForeignKey( + Person, + on_delete=models.CASCADE, + related_name="membership_invites", + ) invite_reason = models.CharField(max_length=64) ``Membership`` has *two* foreign keys to ``Person`` (``person`` and @@ -1577,12 +1623,18 @@ relationship at the database level. ``OneToOneField`` ----------------- -.. class:: OneToOneField(othermodel, parent_link=False, **options) +.. class:: OneToOneField(othermodel, on_delete, parent_link=False, **options) A one-to-one relationship. Conceptually, this is similar to a :class:`ForeignKey` with :attr:`unique=True `, but the "reverse" side of the relation will directly return a single object. +.. versionchanged:: 1.9 + + ``on_delete`` can now be used as the second positional argument (previously + it was typically only passed as a keyword argument). It will be a required + argument in Django 2.0. + This is most useful as the primary key of a model which "extends" another model in some way; :ref:`multi-table-inheritance` is implemented by adding an implicit one-to-one relation from the child @@ -1603,8 +1655,15 @@ With the following example:: from django.db import models class MySpecialUser(models.Model): - user = models.OneToOneField(settings.AUTH_USER_MODEL) - supervisor = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='supervisor_of') + user = models.OneToOneField( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ) + supervisor = models.OneToOneField( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name='supervisor_of', + ) your resulting ``User`` model will have the following attributes:: @@ -1931,6 +1990,6 @@ have boolean values (rather than ``None``) if the field is a relation type .. attribute:: Field.related_model Points to the model the field relates to. For example, ``Author`` in - ``ForeignKey(Author)``. If a field has a generic relation (such as a - ``GenericForeignKey`` or a ``GenericRelation``) then ``related_model`` - will be ``None``. + ``ForeignKey(Author, on_delete=models.CASCADE)``. If a field has a generic + relation (such as a ``GenericForeignKey`` or a ``GenericRelation``) then + ``related_model`` will be ``None``. diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index e9d8e7131c..918ba0966a 100644 --- a/docs/ref/models/options.txt +++ b/docs/ref/models/options.txt @@ -186,7 +186,7 @@ Django quotes column and table names behind the scenes. # ... class Answer(models.Model): - question = models.ForeignKey(Question) + question = models.ForeignKey(Question, on_delete=models.CASCADE) # ... class Meta: diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 3c0e9d0a61..e87a27a9e0 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -350,7 +350,11 @@ related model ordering can change the expected results. Consider this case:: class Event(Model): - parent = models.ForeignKey('self', related_name='children') + parent = models.ForeignKey( + 'self', + on_delete=models.CASCADE, + related_name='children', + ) date = models.DateField() Event.objects.order_by('children__date') @@ -806,11 +810,16 @@ following models:: class Person(models.Model): # ... - hometown = models.ForeignKey(City) + hometown = models.ForeignKey( + City, + on_delete=models.SET_NULL, + blank=True, + null=True, + ) class Book(models.Model): # ... - author = models.ForeignKey(Person) + author = models.ForeignKey(Person, on_delete=models.CASCADE) ... then a call to ``Book.objects.select_related('author__hometown').get(id=4)`` will cache the related ``Person`` *and* the related ``City``:: diff --git a/docs/ref/models/relations.txt b/docs/ref/models/relations.txt index 095ee560c1..9e27e27151 100644 --- a/docs/ref/models/relations.txt +++ b/docs/ref/models/relations.txt @@ -19,7 +19,7 @@ Related objects reference pass class Article(models.Model): - reporter = models.ForeignKey(Reporter) + reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) In the above example, the methods below will be available on the manager ``reporter.article_set``. diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index eecf86325c..17d0edfa3f 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -928,6 +928,19 @@ versions: Its parsing caused bugs with the current syntax, so support for the old syntax will be removed in Django 2.0 following an accelerated deprecation. +``ForeignKey`` and ``OneToOneField`` ``on_delete`` argument +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to increase awareness about cascading model deletion, the +``on_delete`` argument of ``ForeignKey`` and ``OneToOneField`` will be required +in Django 2.0. + +Update models and existing migrations to explicitly set the argument. Since the +default is ``models.CASCADE``, add ``on_delete=models.CASCADE`` to all +``ForeignKey`` and ``OneToOneField``\s that don't use a different option. You +can also pass it as the second positional argument if you don't care about +compatibility with older versions of Django. + ``Field.rel`` changes ~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index 7d3f6fee9e..289237be18 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -312,7 +312,7 @@ you might create an Employee model:: from django.contrib.auth.models import User class Employee(models.Model): - user = models.OneToOneField(User) + user = models.OneToOneField(User, on_delete=models.CASCADE) department = models.CharField(max_length=100) Assuming an existing Employee Fred Smith who has both a User and Employee @@ -443,7 +443,10 @@ different User model. from django.db import models class Article(models.Model): - author = models.ForeignKey(settings.AUTH_USER_MODEL) + author = models.ForeignKey + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ) When connecting to signals sent by the ``User`` model, you should specify the custom model using the :setting:`AUTH_USER_MODEL` setting. For example:: diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt index f3d922ab3a..98b8955020 100644 --- a/docs/topics/class-based-views/generic-display.txt +++ b/docs/topics/class-based-views/generic-display.txt @@ -104,7 +104,7 @@ We'll be using these models:: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField('Author') - publisher = models.ForeignKey(Publisher) + publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) publication_date = models.DateField() Now we need to define a view:: diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt index be087d7758..0ada8db42a 100644 --- a/docs/topics/class-based-views/generic-editing.txt +++ b/docs/topics/class-based-views/generic-editing.txt @@ -204,7 +204,7 @@ the foreign key relation to the model: class Author(models.Model): name = models.CharField(max_length=200) - created_by = models.ForeignKey(User) + created_by = models.ForeignKey(User, on_delete=models.CASCADE) # ... diff --git a/docs/topics/db/examples/many_to_one.txt b/docs/topics/db/examples/many_to_one.txt index e43809fd1c..10020a83cb 100644 --- a/docs/topics/db/examples/many_to_one.txt +++ b/docs/topics/db/examples/many_to_one.txt @@ -17,7 +17,7 @@ To define a many-to-one relationship, use :class:`~django.db.models.ForeignKey`: class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateField() - reporter = models.ForeignKey(Reporter) + reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) def __str__(self): # __unicode__ on Python 2 return self.headline diff --git a/docs/topics/db/examples/one_to_one.txt b/docs/topics/db/examples/one_to_one.txt index f2a3f54508..311ff75d8d 100644 --- a/docs/topics/db/examples/one_to_one.txt +++ b/docs/topics/db/examples/one_to_one.txt @@ -16,7 +16,11 @@ In this example, a ``Place`` optionally can be a ``Restaurant``:: return "%s the place" % self.name class Restaurant(models.Model): - place = models.OneToOneField(Place, primary_key=True) + place = models.OneToOneField( + Place, + on_delete=models.CASCADE, + primary_key=True, + ) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) @@ -24,7 +28,7 @@ In this example, a ``Place`` optionally can be a ``Restaurant``:: return "%s the restaurant" % self.place.name class Waiter(models.Model): - restaurant = models.ForeignKey(Restaurant) + restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE) name = models.CharField(max_length=50) def __str__(self): # __unicode__ on Python 2 diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index 64d484e85d..bd46a34c07 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -87,7 +87,7 @@ returns a list of all ``OpinionPoll`` objects, each with an extra objects = PollManager() class Response(models.Model): - poll = models.ForeignKey(OpinionPoll) + poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE) person_name = models.CharField(max_length=50) response = models.TextField() diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index c21f231808..ed13e46374 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -99,7 +99,7 @@ Example:: instrument = models.CharField(max_length=100) class Album(models.Model): - artist = models.ForeignKey(Musician) + artist = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField() @@ -281,9 +281,17 @@ In this example, the verbose name is ``"first name"``:: :class:`~django.db.models.OneToOneField` require the first argument to be a model class, so use the :attr:`~Field.verbose_name` keyword argument:: - poll = models.ForeignKey(Poll, verbose_name="the related poll") + poll = models.ForeignKey( + Poll, + on_delete=models.CASCADE, + verbose_name="the related poll", + ) sites = models.ManyToManyField(Site, verbose_name="list of sites") - place = models.OneToOneField(Place, verbose_name="related place") + place = models.OneToOneField( + Place, + on_delete=models.CASCADE, + verbose_name="related place", + ) The convention is not to capitalize the first letter of the :attr:`~Field.verbose_name`. Django will automatically capitalize the first @@ -317,7 +325,7 @@ For example, if a ``Car`` model has a ``Manufacturer`` -- that is, a pass class Car(models.Model): - manufacturer = models.ForeignKey(Manufacturer) + manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ... You can also create :ref:`recursive relationships ` (an @@ -331,7 +339,10 @@ above) be the name of the model, lowercase. You can, of course, call the field whatever you want. For example:: class Car(models.Model): - company_that_makes_it = models.ForeignKey(Manufacturer) + company_that_makes_it = models.ForeignKey( + Manufacturer, + on_delete=models.CASCADE, + ) # ... .. seealso:: @@ -445,8 +456,8 @@ something like this:: return self.name class Membership(models.Model): - person = models.ForeignKey(Person) - group = models.ForeignKey(Group) + person = models.ForeignKey(Person, on_delete=models.CASCADE) + group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64) @@ -621,7 +632,12 @@ just refer to the other model class wherever needed. For example:: class Restaurant(models.Model): # ... - zip_code = models.ForeignKey(ZipCode) + zip_code = models.ForeignKey( + ZipCode, + on_delete=models.SET_NULL, + blank=True, + null=True, + ) Field name restrictions ----------------------- diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index c7ff96c8e3..d7617e8b48 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -1160,8 +1160,8 @@ Example:: You can override the ``FOO_set`` name by setting the :attr:`~django.db.models.ForeignKey.related_name` parameter in the :class:`~django.db.models.ForeignKey` definition. For example, if the ``Entry`` -model was altered to ``blog = ForeignKey(Blog, related_name='entries')``, the -above example code would look like this:: +model was altered to ``blog = ForeignKey(Blog, on_delete=models.CASCADE, +related_name='entries')``, the above example code would look like this:: >>> b = Blog.objects.get(id=1) >>> b.entries.all() # Returns all Entry objects related to Blog. @@ -1284,7 +1284,7 @@ model. For example:: class EntryDetail(models.Model): - entry = models.OneToOneField(Entry) + entry = models.OneToOneField(Entry, on_delete=models.CASCADE) details = models.TextField() ed = EntryDetail.objects.get(id=2) diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index 2e75695f53..e9898c6fff 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -1119,7 +1119,7 @@ you have these two models:: name = models.CharField(max_length=100) class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, on_delete=models.CASCADE) title = models.CharField(max_length=100) If you want to create a formset that allows you to edit books belonging to @@ -1178,8 +1178,16 @@ need to resolve the ambiguity manually using ``fk_name``. For example, consider the following model:: class Friendship(models.Model): - from_friend = models.ForeignKey(Friend, related_name='from_friends') - to_friend = models.ForeignKey(Friend, related_name='friends') + from_friend = models.ForeignKey( + Friend, + on_delete=models.CASCADE, + related_name='from_friends', + ) + to_friend = models.ForeignKey( + Friend, + on_delete=models.CASCADE, + related_name='friends', + ) length_in_months = models.IntegerField() To resolve this, you can use ``fk_name`` to diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index 79b466ee39..d976ddf2ef 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -355,8 +355,12 @@ You can mark names of :class:`~django.db.models.ForeignKey`, their :attr:`~django.db.models.Options.verbose_name` options:: class MyThing(models.Model): - kind = models.ForeignKey(ThingKind, related_name='kinds', - verbose_name=_('kind')) + kind = models.ForeignKey( + ThingKind, + on_delete=models.CASCADE, + related_name='kinds', + verbose_name=_('kind'), + ) Just like you would do in :attr:`~django.db.models.Options.verbose_name` you should provide a lowercase verbose name text for the relation as Django will @@ -391,8 +395,12 @@ with the ``short_description`` attribute:: from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): - kind = models.ForeignKey(ThingKind, related_name='kinds', - verbose_name=_('kind')) + kind = models.ForeignKey( + ThingKind, + on_delete=models.CASCADE, + related_name='kinds', + verbose_name=_('kind'), + ) def is_mouse(self): return self.kind.type == MOUSE_TYPE diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index b48c625fe8..e34553699d 100644 --- a/docs/topics/serialization.txt +++ b/docs/topics/serialization.txt @@ -344,7 +344,7 @@ Consider the following two models:: class Book(models.Model): name = models.CharField(max_length=100) - author = models.ForeignKey(Person) + author = models.ForeignKey(Person, on_delete=models.CASCADE) Ordinarily, serialized data for ``Book`` would use an integer to refer to the author. For example, in JSON, a Book might be serialized as:: @@ -514,7 +514,7 @@ example above:: class Book(models.Model): name = models.CharField(max_length=100) - author = models.ForeignKey(Person) + author = models.ForeignKey(Person, on_delete=models.CASCADE) def natural_key(self): return (self.name,) + self.author.natural_key() diff --git a/tests/admin_changelist/models.py b/tests/admin_changelist/models.py index aa4241c4d3..fb5f03cbd6 100644 --- a/tests/admin_changelist/models.py +++ b/tests/admin_changelist/models.py @@ -12,7 +12,7 @@ class Parent(models.Model): class Child(models.Model): - parent = models.ForeignKey(Parent, editable=False, null=True) + parent = models.ForeignKey(Parent, models.SET_NULL, editable=False, null=True) name = models.CharField(max_length=30, blank=True) age = models.IntegerField(null=True, blank=True) @@ -46,12 +46,12 @@ class Group(models.Model): class Concert(models.Model): name = models.CharField(max_length=30) - group = models.ForeignKey(Group) + group = models.ForeignKey(Group, models.CASCADE) class Membership(models.Model): - music = models.ForeignKey(Musician) - group = models.ForeignKey(Group) + music = models.ForeignKey(Musician, models.CASCADE) + group = models.ForeignKey(Group, models.CASCADE) role = models.CharField(max_length=15) @@ -69,8 +69,8 @@ class ChordsBand(models.Model): class Invitation(models.Model): - player = models.ForeignKey(ChordsMusician) - band = models.ForeignKey(ChordsBand) + player = models.ForeignKey(ChordsMusician, models.CASCADE) + band = models.ForeignKey(ChordsBand, models.CASCADE) instrument = models.CharField(max_length=15) @@ -84,7 +84,7 @@ class Swallow(models.Model): class SwallowOneToOne(models.Model): - swallow = models.OneToOneField(Swallow) + swallow = models.OneToOneField(Swallow, models.CASCADE) class UnorderedObject(models.Model): diff --git a/tests/admin_checks/models.py b/tests/admin_checks/models.py index 835c26c0dc..822d695e4d 100644 --- a/tests/admin_checks/models.py +++ b/tests/admin_checks/models.py @@ -15,7 +15,7 @@ class Album(models.Model): @python_2_unicode_compatible class Song(models.Model): title = models.CharField(max_length=150) - album = models.ForeignKey(Album) + album = models.ForeignKey(Album, models.CASCADE) original_release = models.DateField(editable=False) class Meta: @@ -30,8 +30,8 @@ class Song(models.Model): class TwoAlbumFKAndAnE(models.Model): - album1 = models.ForeignKey(Album, related_name="album1_set") - album2 = models.ForeignKey(Album, related_name="album2_set") + album1 = models.ForeignKey(Album, models.CASCADE, related_name="album1_set") + album2 = models.ForeignKey(Album, models.CASCADE, related_name="album2_set") e = models.CharField(max_length=1) @@ -47,8 +47,8 @@ class Book(models.Model): class AuthorsBooks(models.Model): - author = models.ForeignKey(Author) - book = models.ForeignKey(Book) + author = models.ForeignKey(Author, models.CASCADE) + book = models.ForeignKey(Book, models.CASCADE) featured = models.BooleanField() @@ -57,12 +57,12 @@ class State(models.Model): class City(models.Model): - state = models.ForeignKey(State) + state = models.ForeignKey(State, models.CASCADE) class Influence(models.Model): name = models.TextField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') diff --git a/tests/admin_docs/models.py b/tests/admin_docs/models.py index 89a9e8c98e..6dff4358c2 100644 --- a/tests/admin_docs/models.py +++ b/tests/admin_docs/models.py @@ -38,8 +38,8 @@ class Person(models.Model): """ first_name = models.CharField(max_length=200, help_text="The person's first name") last_name = models.CharField(max_length=200, help_text="The person's last name") - company = models.ForeignKey(Company, help_text="place of work") - family = models.ForeignKey(Family, related_name='+', null=True) + company = models.ForeignKey(Company, models.CASCADE, help_text="place of work") + family = models.ForeignKey(Family, models.SET_NULL, related_name='+', null=True) groups = models.ManyToManyField(Group, help_text="has membership") def _get_full_name(self): diff --git a/tests/admin_filters/models.py b/tests/admin_filters/models.py index 588d90ea48..9f89809349 100644 --- a/tests/admin_filters/models.py +++ b/tests/admin_filters/models.py @@ -13,7 +13,13 @@ from django.utils.encoding import python_2_unicode_compatible class Book(models.Model): title = models.CharField(max_length=50) year = models.PositiveIntegerField(null=True, blank=True) - author = models.ForeignKey(User, verbose_name="Verbose Author", related_name='books_authored', blank=True, null=True) + author = models.ForeignKey( + User, + models.SET_NULL, + verbose_name="Verbose Author", + related_name='books_authored', + blank=True, null=True, + ) contributors = models.ManyToManyField(User, verbose_name="Verbose Contributors", related_name='books_contributed', blank=True) is_best_seller = models.NullBooleanField(default=0) date_registered = models.DateField(null=True) @@ -34,7 +40,7 @@ class Department(models.Model): @python_2_unicode_compatible class Employee(models.Model): - department = models.ForeignKey(Department, to_field="code") + department = models.ForeignKey(Department, models.CASCADE, to_field="code") name = models.CharField(max_length=100) def __str__(self): @@ -44,7 +50,7 @@ class Employee(models.Model): @python_2_unicode_compatible class TaggedItem(models.Model): tag = models.SlugField() - content_type = models.ForeignKey(ContentType, related_name='tagged_items') + content_type = models.ForeignKey(ContentType, models.CASCADE, related_name='tagged_items') object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') diff --git a/tests/admin_inlines/models.py b/tests/admin_inlines/models.py index d1003f607a..15297c521f 100644 --- a/tests/admin_inlines/models.py +++ b/tests/admin_inlines/models.py @@ -31,9 +31,9 @@ class Teacher(models.Model): @python_2_unicode_compatible class Child(models.Model): name = models.CharField(max_length=50) - teacher = models.ForeignKey(Teacher) + teacher = models.ForeignKey(Teacher, models.CASCADE) - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() parent = GenericForeignKey() @@ -52,7 +52,7 @@ class Author(models.Model): class NonAutoPKBook(models.Model): rand_pk = models.IntegerField(primary_key=True, editable=False) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=50) def save(self, *args, **kwargs): @@ -65,7 +65,7 @@ class NonAutoPKBook(models.Model): class EditablePKBook(models.Model): manual_pk = models.IntegerField(primary_key=True) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=50) @@ -75,7 +75,7 @@ class Holder(models.Model): class Inner(models.Model): dummy = models.IntegerField() - holder = models.ForeignKey(Holder) + holder = models.ForeignKey(Holder, models.CASCADE) readonly = models.CharField("Inner readonly label", max_length=1) def get_absolute_url(self): @@ -88,7 +88,7 @@ class Holder2(models.Model): class Inner2(models.Model): dummy = models.IntegerField() - holder = models.ForeignKey(Holder2) + holder = models.ForeignKey(Holder2, models.CASCADE) class Holder3(models.Model): @@ -97,7 +97,7 @@ class Holder3(models.Model): class Inner3(models.Model): dummy = models.IntegerField() - holder = models.ForeignKey(Holder3) + holder = models.ForeignKey(Holder3, models.CASCADE) # Models for ticket #8190 @@ -108,12 +108,12 @@ class Holder4(models.Model): class Inner4Stacked(models.Model): dummy = models.IntegerField(help_text="Awesome stacked help text is awesome.") - holder = models.ForeignKey(Holder4) + holder = models.ForeignKey(Holder4, models.CASCADE) class Inner4Tabular(models.Model): dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.") - holder = models.ForeignKey(Holder4) + holder = models.ForeignKey(Holder4, models.CASCADE) # Models for #12749 @@ -127,13 +127,13 @@ class OutfitItem(models.Model): class Fashionista(models.Model): - person = models.OneToOneField(Person, primary_key=True) + person = models.OneToOneField(Person, models.CASCADE, primary_key=True) weaknesses = models.ManyToManyField(OutfitItem, through='ShoppingWeakness', blank=True) class ShoppingWeakness(models.Model): - fashionista = models.ForeignKey(Fashionista) - item = models.ForeignKey(OutfitItem) + fashionista = models.ForeignKey(Fashionista, models.CASCADE) + item = models.ForeignKey(OutfitItem, models.CASCADE) # Models for #13510 @@ -143,7 +143,7 @@ class TitleCollection(models.Model): class Title(models.Model): - collection = models.ForeignKey(TitleCollection, blank=True, null=True) + collection = models.ForeignKey(TitleCollection, models.SET_NULL, blank=True, null=True) title1 = models.CharField(max_length=100) title2 = models.CharField(max_length=100) @@ -155,7 +155,7 @@ class Poll(models.Model): class Question(models.Model): - poll = models.ForeignKey(Poll) + poll = models.ForeignKey(Poll, models.CASCADE) class Novel(models.Model): @@ -164,14 +164,14 @@ class Novel(models.Model): class Chapter(models.Model): name = models.CharField(max_length=40) - novel = models.ForeignKey(Novel) + novel = models.ForeignKey(Novel, models.CASCADE) class FootNote(models.Model): """ Model added for ticket 19838 """ - chapter = models.ForeignKey(Chapter, on_delete=models.PROTECT) + chapter = models.ForeignKey(Chapter, models.PROTECT) note = models.CharField(max_length=40) # Models for #16838 @@ -183,17 +183,17 @@ class CapoFamiglia(models.Model): class Consigliere(models.Model): name = models.CharField(max_length=100, help_text='Help text for Consigliere') - capo_famiglia = models.ForeignKey(CapoFamiglia, related_name='+') + capo_famiglia = models.ForeignKey(CapoFamiglia, models.CASCADE, related_name='+') class SottoCapo(models.Model): name = models.CharField(max_length=100) - capo_famiglia = models.ForeignKey(CapoFamiglia, related_name='+') + capo_famiglia = models.ForeignKey(CapoFamiglia, models.CASCADE, related_name='+') class ReadOnlyInline(models.Model): name = models.CharField(max_length=100, help_text='Help text for ReadOnlyInline') - capo_famiglia = models.ForeignKey(CapoFamiglia) + capo_famiglia = models.ForeignKey(CapoFamiglia, models.CASCADE) # Models for #18433 @@ -206,7 +206,7 @@ class ParentModelWithCustomPk(models.Model): class ChildModel1(models.Model): my_own_pk = models.CharField(max_length=100, primary_key=True) name = models.CharField(max_length=100) - parent = models.ForeignKey(ParentModelWithCustomPk) + parent = models.ForeignKey(ParentModelWithCustomPk, models.CASCADE) def get_absolute_url(self): return '/child_model1/' @@ -215,7 +215,7 @@ class ChildModel1(models.Model): class ChildModel2(models.Model): my_own_pk = models.CharField(max_length=100, primary_key=True) name = models.CharField(max_length=100) - parent = models.ForeignKey(ParentModelWithCustomPk) + parent = models.ForeignKey(ParentModelWithCustomPk, models.CASCADE) def get_absolute_url(self): return '/child_model2/' @@ -224,7 +224,7 @@ class ChildModel2(models.Model): # Models for #19425 class BinaryTree(models.Model): name = models.CharField(max_length=100) - parent = models.ForeignKey('self', null=True, blank=True) + parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True) # Models for #19524 @@ -238,7 +238,7 @@ class ExtraTerrestrial(LifeForm): class Sighting(models.Model): - et = models.ForeignKey(ExtraTerrestrial) + et = models.ForeignKey(ExtraTerrestrial, models.CASCADE) place = models.CharField(max_length=100) @@ -250,7 +250,7 @@ class SomeParentModel(models.Model): class SomeChildModel(models.Model): name = models.CharField(max_length=1) position = models.PositiveIntegerField() - parent = models.ForeignKey(SomeParentModel) + parent = models.ForeignKey(SomeParentModel, models.CASCADE) # Other models @@ -260,6 +260,6 @@ class ProfileCollection(models.Model): class Profile(models.Model): - collection = models.ForeignKey(ProfileCollection, blank=True, null=True) + collection = models.ForeignKey(ProfileCollection, models.SET_NULL, blank=True, null=True) first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) diff --git a/tests/admin_ordering/models.py b/tests/admin_ordering/models.py index 91831edc2b..cd26f2a710 100644 --- a/tests/admin_ordering/models.py +++ b/tests/admin_ordering/models.py @@ -13,7 +13,7 @@ class Band(models.Model): class Song(models.Model): - band = models.ForeignKey(Band) + band = models.ForeignKey(Band, models.CASCADE) name = models.CharField(max_length=100) duration = models.IntegerField() other_interpreters = models.ManyToManyField(Band, related_name='covers') diff --git a/tests/admin_scripts/app_with_import/models.py b/tests/admin_scripts/app_with_import/models.py index 3741541628..bf49e8f477 100644 --- a/tests/admin_scripts/app_with_import/models.py +++ b/tests/admin_scripts/app_with_import/models.py @@ -5,4 +5,4 @@ from django.db import models # Regression for #13368. This is an example of a model # that imports a class that has an abstract base class. class UserProfile(models.Model): - user = models.OneToOneField(User, primary_key=True) + user = models.OneToOneField(User, models.CASCADE, primary_key=True) diff --git a/tests/admin_utils/models.py b/tests/admin_utils/models.py index ce845c64eb..c328ec50a2 100644 --- a/tests/admin_utils/models.py +++ b/tests/admin_utils/models.py @@ -15,7 +15,7 @@ class Article(models.Model): """ A simple Article model for testing """ - site = models.ForeignKey(Site, related_name="admin_articles") + site = models.ForeignKey(Site, models.CASCADE, related_name="admin_articles") title = models.CharField(max_length=100) title2 = models.CharField(max_length=100, verbose_name="another name") created = models.DateTimeField() @@ -31,7 +31,7 @@ class Article(models.Model): @python_2_unicode_compatible class Count(models.Model): num = models.PositiveSmallIntegerField() - parent = models.ForeignKey('self', null=True) + parent = models.ForeignKey('self', models.CASCADE, null=True) def __str__(self): return six.text_type(self.num) @@ -42,11 +42,11 @@ class Event(models.Model): class Location(models.Model): - event = models.OneToOneField(Event, verbose_name='awesome event') + event = models.OneToOneField(Event, models.CASCADE, verbose_name='awesome event') class Guest(models.Model): - event = models.OneToOneField(Event) + event = models.OneToOneField(Event, models.CASCADE) name = models.CharField(max_length=255) class Meta: @@ -54,7 +54,7 @@ class Guest(models.Model): class EventGuide(models.Model): - event = models.ForeignKey(Event, on_delete=models.DO_NOTHING) + event = models.ForeignKey(Event, models.DO_NOTHING) class Vehicle(models.Model): @@ -62,7 +62,12 @@ class Vehicle(models.Model): class VehicleMixin(Vehicle): - vehicle = models.OneToOneField(Vehicle, parent_link=True, related_name='vehicle_%(app_label)s_%(class)s') + vehicle = models.OneToOneField( + Vehicle, + models.CASCADE, + parent_link=True, + related_name='vehicle_%(app_label)s_%(class)s', + ) class Meta: abstract = True diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py index 0df249febe..fd1b8b33a3 100644 --- a/tests/admin_views/models.py +++ b/tests/admin_views/models.py @@ -39,8 +39,8 @@ class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() date = models.DateTimeField() - section = models.ForeignKey(Section, null=True, blank=True) - sub_section = models.ForeignKey(Section, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') + section = models.ForeignKey(Section, models.CASCADE, null=True, blank=True) + sub_section = models.ForeignKey(Section, models.SET_NULL, null=True, blank=True, related_name='+') def __str__(self): return self.title @@ -70,7 +70,7 @@ class Book(models.Model): @python_2_unicode_compatible class Promo(models.Model): name = models.CharField(max_length=100, verbose_name='¿Name?') - book = models.ForeignKey(Book) + book = models.ForeignKey(Book, models.CASCADE) def __str__(self): return self.name @@ -80,7 +80,7 @@ class Promo(models.Model): class Chapter(models.Model): title = models.CharField(max_length=100, verbose_name='¿Title?') content = models.TextField() - book = models.ForeignKey(Book) + book = models.ForeignKey(Book, models.CASCADE) def __str__(self): return self.title @@ -92,7 +92,7 @@ class Chapter(models.Model): @python_2_unicode_compatible class ChapterXtra1(models.Model): - chap = models.OneToOneField(Chapter, verbose_name='¿Chap?') + chap = models.OneToOneField(Chapter, models.CASCADE, verbose_name='¿Chap?') xtra = models.CharField(max_length=100, verbose_name='¿Xtra?') def __str__(self): @@ -101,7 +101,7 @@ class ChapterXtra1(models.Model): @python_2_unicode_compatible class ChapterXtra2(models.Model): - chap = models.OneToOneField(Chapter, verbose_name='¿Chap?') + chap = models.OneToOneField(Chapter, models.CASCADE, verbose_name='¿Chap?') xtra = models.CharField(max_length=100, verbose_name='¿Xtra?') def __str__(self): @@ -146,7 +146,7 @@ class Color2(Color): @python_2_unicode_compatible class Thing(models.Model): title = models.CharField(max_length=20) - color = models.ForeignKey(Color, limit_choices_to={'warm': True}) + color = models.ForeignKey(Color, models.CASCADE, limit_choices_to={'warm': True}) pub_date = models.DateField(blank=True, null=True) def __str__(self): @@ -166,7 +166,7 @@ class Actor(models.Model): @python_2_unicode_compatible class Inquisition(models.Model): expected = models.BooleanField(default=False) - leader = models.ForeignKey(Actor) + leader = models.ForeignKey(Actor, models.CASCADE) country = models.CharField(max_length=20) def __str__(self): @@ -176,12 +176,27 @@ class Inquisition(models.Model): @python_2_unicode_compatible class Sketch(models.Model): title = models.CharField(max_length=100) - inquisition = models.ForeignKey(Inquisition, limit_choices_to={'leader__name': 'Palin', - 'leader__age': 27, - 'expected': False, - }) - defendant0 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': False}, related_name='as_defendant0') - defendant1 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': True}, related_name='as_defendant1') + inquisition = models.ForeignKey( + Inquisition, + models.CASCADE, + limit_choices_to={ + 'leader__name': 'Palin', + 'leader__age': 27, + 'expected': False, + }, + ) + defendant0 = models.ForeignKey( + Actor, + models.CASCADE, + limit_choices_to={'title__isnull': False}, + related_name='as_defendant0', + ) + defendant1 = models.ForeignKey( + Actor, + models.CASCADE, + limit_choices_to={'title__isnull': True}, + related_name='as_defendant1', + ) def __str__(self): return self.title @@ -207,7 +222,12 @@ class Character(models.Model): @python_2_unicode_compatible class StumpJoke(models.Model): variation = models.CharField(max_length=100) - most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+") + most_recently_fooled = models.ForeignKey( + Character, + models.CASCADE, + limit_choices_to=today_callable_dict, + related_name="+", + ) has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+") def __str__(self): @@ -259,7 +279,7 @@ class Account(models.Model): types of accounts. """ username = models.CharField(blank=False, max_length=80) - persona = models.ForeignKey(Persona, related_name="accounts") + persona = models.ForeignKey(Persona, models.CASCADE, related_name="accounts") servicename = 'generic service' def __str__(self): @@ -305,7 +325,7 @@ class Podcast(Media): class Vodcast(Media): - media = models.OneToOneField(Media, primary_key=True, parent_link=True) + media = models.OneToOneField(Media, models.CASCADE, primary_key=True, parent_link=True) released = models.BooleanField(default=False) @@ -318,7 +338,7 @@ class Parent(models.Model): class Child(models.Model): - parent = models.ForeignKey(Parent, editable=False) + parent = models.ForeignKey(Parent, models.CASCADE, editable=False) name = models.CharField(max_length=30, blank=True) def clean(self): @@ -343,7 +363,7 @@ class Gallery(models.Model): class Picture(models.Model): name = models.CharField(max_length=100) image = models.FileField(storage=temp_storage, upload_to='test_upload') - gallery = models.ForeignKey(Gallery, related_name="pictures") + gallery = models.ForeignKey(Gallery, models.CASCADE, related_name="pictures") class Language(models.Model): @@ -362,7 +382,7 @@ class Title(models.Model): class TitleTranslation(models.Model): - title = models.ForeignKey(Title) + title = models.ForeignKey(Title, models.CASCADE) text = models.CharField(max_length=100) @@ -371,7 +391,7 @@ class Recommender(Title): class Recommendation(Title): - recommender = models.ForeignKey(Recommender) + recommender = models.ForeignKey(Recommender, models.CASCADE) class Collector(models.Model): @@ -379,25 +399,25 @@ class Collector(models.Model): class Widget(models.Model): - owner = models.ForeignKey(Collector) + owner = models.ForeignKey(Collector, models.CASCADE) name = models.CharField(max_length=100) class DooHickey(models.Model): code = models.CharField(max_length=10, primary_key=True) - owner = models.ForeignKey(Collector) + owner = models.ForeignKey(Collector, models.CASCADE) name = models.CharField(max_length=100) class Grommet(models.Model): code = models.AutoField(primary_key=True) - owner = models.ForeignKey(Collector) + owner = models.ForeignKey(Collector, models.CASCADE) name = models.CharField(max_length=100) class Whatsit(models.Model): index = models.IntegerField(primary_key=True) - owner = models.ForeignKey(Collector) + owner = models.ForeignKey(Collector, models.CASCADE) name = models.CharField(max_length=100) @@ -406,13 +426,13 @@ class Doodad(models.Model): class FancyDoodad(Doodad): - owner = models.ForeignKey(Collector) + owner = models.ForeignKey(Collector, models.CASCADE) expensive = models.BooleanField(default=True) @python_2_unicode_compatible class Category(models.Model): - collector = models.ForeignKey(Collector) + collector = models.ForeignKey(Collector, models.CASCADE) order = models.PositiveIntegerField() class Meta: @@ -429,7 +449,7 @@ def link_posted_default(): class Link(models.Model): posted = models.DateField(default=link_posted_default) url = models.URLField() - post = models.ForeignKey("Post") + post = models.ForeignKey("Post", models.CASCADE) class PrePopulatedPost(models.Model): @@ -439,7 +459,7 @@ class PrePopulatedPost(models.Model): class PrePopulatedSubPost(models.Model): - post = models.ForeignKey(PrePopulatedPost) + post = models.ForeignKey(PrePopulatedPost, models.CASCADE) subtitle = models.CharField(max_length=100) subslug = models.SlugField() @@ -488,7 +508,7 @@ class SuperVillain(Villain): class FunkyTag(models.Model): "Because we all know there's only one real use case for GFKs." name = models.CharField(max_length=25) - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') @@ -499,8 +519,8 @@ class FunkyTag(models.Model): @python_2_unicode_compatible class Plot(models.Model): name = models.CharField(max_length=100) - team_leader = models.ForeignKey(Villain, related_name='lead_plots') - contact = models.ForeignKey(Villain, related_name='contact_plots') + team_leader = models.ForeignKey(Villain, models.CASCADE, related_name='lead_plots') + contact = models.ForeignKey(Villain, models.CASCADE, related_name='contact_plots') tags = GenericRelation(FunkyTag) def __str__(self): @@ -510,7 +530,7 @@ class Plot(models.Model): @python_2_unicode_compatible class PlotDetails(models.Model): details = models.CharField(max_length=100) - plot = models.OneToOneField(Plot) + plot = models.OneToOneField(Plot, models.CASCADE) def __str__(self): return self.details @@ -520,7 +540,7 @@ class PlotDetails(models.Model): class SecretHideout(models.Model): """ Secret! Not registered with the admin! """ location = models.CharField(max_length=100) - villain = models.ForeignKey(Villain) + villain = models.ForeignKey(Villain, models.CASCADE) def __str__(self): return self.location @@ -530,7 +550,7 @@ class SecretHideout(models.Model): class SuperSecretHideout(models.Model): """ Secret! Not registered with the admin! """ location = models.CharField(max_length=100) - supervillain = models.ForeignKey(SuperVillain) + supervillain = models.ForeignKey(SuperVillain, models.CASCADE) def __str__(self): return self.location @@ -539,7 +559,7 @@ class SuperSecretHideout(models.Model): @python_2_unicode_compatible class CyclicOne(models.Model): name = models.CharField(max_length=25) - two = models.ForeignKey('CyclicTwo') + two = models.ForeignKey('CyclicTwo', models.CASCADE) def __str__(self): return self.name @@ -548,7 +568,7 @@ class CyclicOne(models.Model): @python_2_unicode_compatible class CyclicTwo(models.Model): name = models.CharField(max_length=25) - one = models.ForeignKey(CyclicOne) + one = models.ForeignKey(CyclicOne, models.CASCADE) def __str__(self): return self.name @@ -564,7 +584,7 @@ class Pizza(models.Model): class Album(models.Model): - owner = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) + owner = models.ForeignKey(User, models.SET_NULL, null=True, blank=True) title = models.CharField(max_length=30) @@ -574,7 +594,7 @@ class Employee(Person): class WorkHour(models.Model): datum = models.DateField() - employee = models.ForeignKey(Employee) + employee = models.ForeignKey(Employee, models.CASCADE) class Question(models.Model): @@ -583,7 +603,7 @@ class Question(models.Model): @python_2_unicode_compatible class Answer(models.Model): - question = models.ForeignKey(Question, on_delete=models.PROTECT) + question = models.ForeignKey(Question, models.PROTECT) answer = models.CharField(max_length=20) def __str__(self): @@ -722,7 +742,7 @@ class MainPrepopulated(models.Model): class RelatedPrepopulated(models.Model): - parent = models.ForeignKey(MainPrepopulated) + parent = models.ForeignKey(MainPrepopulated, models.CASCADE) name = models.CharField(max_length=75) pubdate = models.DateField() status = models.CharField( @@ -790,7 +810,7 @@ class DependentChild(models.Model): Model that depends on validation of the parent class for one of its fields to validate during clean """ - parent = models.ForeignKey(ParentWithDependentChildren) + parent = models.ForeignKey(ParentWithDependentChildren, models.CASCADE) family_name = models.CharField(max_length=255) @@ -824,7 +844,7 @@ class State(models.Model): class City(models.Model): - state = models.ForeignKey(State) + state = models.ForeignKey(State, models.CASCADE) name = models.CharField(max_length=100) def get_absolute_url(self): @@ -832,7 +852,7 @@ class City(models.Model): class Restaurant(models.Model): - city = models.ForeignKey(City) + city = models.ForeignKey(City, models.CASCADE) name = models.CharField(max_length=100) def get_absolute_url(self): @@ -840,7 +860,7 @@ class Restaurant(models.Model): class Worker(models.Model): - work_at = models.ForeignKey(Restaurant) + work_at = models.ForeignKey(Restaurant, models.CASCADE) name = models.CharField(max_length=50) surname = models.CharField(max_length=50) @@ -852,7 +872,10 @@ class ReferencedByParent(models.Model): class ParentWithFK(models.Model): fk = models.ForeignKey( - ReferencedByParent, to_field='name', related_name='hidden+', + ReferencedByParent, + models.CASCADE, + to_field='name', + related_name='hidden+', ) @@ -867,7 +890,10 @@ class ReferencedByInline(models.Model): class InlineReference(models.Model): fk = models.ForeignKey( - ReferencedByInline, to_field='name', related_name='hidden+', + ReferencedByInline, + models.CASCADE, + to_field='name', + related_name='hidden+', ) @@ -886,8 +912,8 @@ class Ingredient(models.Model): class RecipeIngredient(models.Model): - ingredient = models.ForeignKey(Ingredient, to_field='iname') - recipe = models.ForeignKey(Recipe, to_field='rname') + ingredient = models.ForeignKey(Ingredient, models.CASCADE, to_field='iname') + recipe = models.ForeignKey(Recipe, models.CASCADE, to_field='rname') # Model for #23839 diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py index 5f990bdce3..d795fea007 100644 --- a/tests/admin_widgets/models.py +++ b/tests/admin_widgets/models.py @@ -32,7 +32,7 @@ class Band(models.Model): @python_2_unicode_compatible class Album(models.Model): - band = models.ForeignKey(Band) + band = models.ForeignKey(Band, models.CASCADE) name = models.CharField(max_length=100) cover_art = models.FileField(upload_to='albums') backside_art = MyFileField(upload_to='albums_back', null=True) @@ -49,7 +49,7 @@ class HiddenInventoryManager(models.Manager): @python_2_unicode_compatible class Inventory(models.Model): barcode = models.PositiveIntegerField(unique=True) - parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) + parent = models.ForeignKey('self', models.SET_NULL, to_field='barcode', blank=True, null=True) name = models.CharField(blank=False, max_length=20) hidden = models.BooleanField(default=False) @@ -62,7 +62,12 @@ class Inventory(models.Model): class Event(models.Model): - main_band = models.ForeignKey(Band, limit_choices_to=models.Q(pk__gt=0), related_name='events_main_band_at') + main_band = models.ForeignKey( + Band, + models.CASCADE, + limit_choices_to=models.Q(pk__gt=0), + related_name='events_main_band_at', + ) supporting_bands = models.ManyToManyField(Band, blank=True, related_name='events_supporting_band_at') start_date = models.DateField(blank=True, null=True) start_time = models.TimeField(blank=True, null=True) @@ -73,7 +78,7 @@ class Event(models.Model): @python_2_unicode_compatible class Car(models.Model): - owner = models.ForeignKey(User) + owner = models.ForeignKey(User, models.CASCADE) make = models.CharField(max_length=30) model = models.CharField(max_length=30) @@ -85,7 +90,7 @@ class CarTire(models.Model): """ A single car tire. This to test that a user can only select their own cars. """ - car = models.ForeignKey(Car) + car = models.ForeignKey(Car, models.CASCADE) class Honeycomb(models.Model): @@ -98,7 +103,7 @@ class Bee(models.Model): (Honeycomb) so the corresponding raw ID widget won't have a magnifying glass link to select related honeycomb instances. """ - honeycomb = models.ForeignKey(Honeycomb) + honeycomb = models.ForeignKey(Honeycomb, models.CASCADE) class Individual(models.Model): @@ -108,8 +113,8 @@ class Individual(models.Model): related instances (rendering will be called programmatically in this case). """ name = models.CharField(max_length=20) - parent = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) - soulmate = models.ForeignKey('self', null=True, on_delete=models.CASCADE, related_name='soulmates') + parent = models.ForeignKey('self', models.SET_NULL, null=True) + soulmate = models.ForeignKey('self', models.CASCADE, null=True, related_name='soulmates') class Company(models.Model): @@ -149,7 +154,7 @@ class School(models.Model): @python_2_unicode_compatible class Profile(models.Model): - user = models.ForeignKey('auth.User', 'username') + user = models.ForeignKey('auth.User', models.CASCADE, to_field='username') def __str__(self): return self.user.username diff --git a/tests/aggregation/models.py b/tests/aggregation/models.py index de9dc5550c..9d47946418 100644 --- a/tests/aggregation/models.py +++ b/tests/aggregation/models.py @@ -31,8 +31,8 @@ class Book(models.Model): rating = models.FloatField() price = models.DecimalField(decimal_places=2, max_digits=6) authors = models.ManyToManyField(Author) - contact = models.ForeignKey(Author, related_name='book_contact_set') - publisher = models.ForeignKey(Publisher) + contact = models.ForeignKey(Author, models.CASCADE, related_name='book_contact_set') + publisher = models.ForeignKey(Publisher, models.CASCADE) pubdate = models.DateField() def __str__(self): diff --git a/tests/aggregation_regress/models.py b/tests/aggregation_regress/models.py index 4d675952c2..e606beb304 100644 --- a/tests/aggregation_regress/models.py +++ b/tests/aggregation_regress/models.py @@ -28,7 +28,7 @@ class Publisher(models.Model): class ItemTag(models.Model): tag = models.CharField(max_length=100) - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') @@ -41,8 +41,8 @@ class Book(models.Model): rating = models.FloatField() price = models.DecimalField(decimal_places=2, max_digits=6) authors = models.ManyToManyField(Author) - contact = models.ForeignKey(Author, related_name='book_contact_set') - publisher = models.ForeignKey(Publisher) + contact = models.ForeignKey(Author, models.CASCADE, related_name='book_contact_set') + publisher = models.ForeignKey(Publisher, models.CASCADE) pubdate = models.DateField() tags = GenericRelation(ItemTag) @@ -72,7 +72,7 @@ class Entries(models.Model): class Clues(models.Model): ID = models.AutoField(primary_key=True) - EntryID = models.ForeignKey(Entries, verbose_name='Entry', db_column='Entry ID') + EntryID = models.ForeignKey(Entries, models.CASCADE, verbose_name='Entry', db_column='Entry ID') Clue = models.CharField(max_length=150) @@ -102,10 +102,10 @@ class Bravo(models.Model): class Charlie(models.Model): - alfa = models.ForeignKey(Alfa, null=True) - bravo = models.ForeignKey(Bravo, null=True) + alfa = models.ForeignKey(Alfa, models.SET_NULL, null=True) + bravo = models.ForeignKey(Bravo, models.SET_NULL, null=True) class SelfRefFK(models.Model): name = models.CharField(max_length=50) - parent = models.ForeignKey('self', null=True, blank=True, related_name='children') + parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True, related_name='children') diff --git a/tests/annotations/models.py b/tests/annotations/models.py index 954c8ad339..1c6faaf884 100644 --- a/tests/annotations/models.py +++ b/tests/annotations/models.py @@ -30,8 +30,8 @@ class Book(models.Model): rating = models.FloatField() price = models.DecimalField(decimal_places=2, max_digits=6) authors = models.ManyToManyField(Author) - contact = models.ForeignKey(Author, related_name='book_contact_set') - publisher = models.ForeignKey(Publisher) + contact = models.ForeignKey(Author, models.CASCADE, related_name='book_contact_set') + publisher = models.ForeignKey(Publisher, models.CASCADE) pubdate = models.DateField() def __str__(self): @@ -65,7 +65,7 @@ class Employee(models.Model): first_name = models.CharField(max_length=20) manager = models.BooleanField(default=False) last_name = models.CharField(max_length=20) - store = models.ForeignKey(Store) + store = models.ForeignKey(Store, models.CASCADE) age = models.IntegerField() salary = models.DecimalField(max_digits=8, decimal_places=2) diff --git a/tests/app_loading/not_installed/models.py b/tests/app_loading/not_installed/models.py index 09cf2ac6ed..44a9d93c98 100644 --- a/tests/app_loading/not_installed/models.py +++ b/tests/app_loading/not_installed/models.py @@ -12,7 +12,7 @@ class RelatedModel(models.Model): class Meta: app_label = 'not_installed' - not_installed = models.ForeignKey(NotInstalledModel) + not_installed = models.ForeignKey(NotInstalledModel, models.CASCADE) class M2MRelatedModel(models.Model): diff --git a/tests/auth_tests/models/with_foreign_key.py b/tests/auth_tests/models/with_foreign_key.py index 21addfc589..2288662905 100644 --- a/tests/auth_tests/models/with_foreign_key.py +++ b/tests/auth_tests/models/with_foreign_key.py @@ -18,9 +18,9 @@ class CustomUserWithFKManager(BaseUserManager): class CustomUserWithFK(AbstractBaseUser): - username = models.ForeignKey(Email, related_name='primary') - email = models.ForeignKey(Email, to_field='email', related_name='secondary') - group = models.ForeignKey(Group) + username = models.ForeignKey(Email, models.CASCADE, related_name='primary') + email = models.ForeignKey(Email, models.CASCADE, to_field='email', related_name='secondary') + group = models.ForeignKey(Group, models.CASCADE) custom_objects = CustomUserWithFKManager() diff --git a/tests/backends/models.py b/tests/backends/models.py index d69416962d..ed21309354 100644 --- a/tests/backends/models.py +++ b/tests/backends/models.py @@ -44,7 +44,7 @@ class VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ(models.Model): class Tag(models.Model): name = models.CharField(max_length=30) - content_type = models.ForeignKey(ContentType, related_name='backend_tags') + content_type = models.ForeignKey(ContentType, models.CASCADE, related_name='backend_tags') object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') @@ -76,9 +76,13 @@ class ReporterProxy(Reporter): class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateField() - reporter = models.ForeignKey(Reporter) - reporter_proxy = models.ForeignKey(ReporterProxy, null=True, - related_name='reporter_proxy') + reporter = models.ForeignKey(Reporter, models.CASCADE) + reporter_proxy = models.ForeignKey( + ReporterProxy, + models.SET_NULL, + null=True, + related_name='reporter_proxy', + ) def __str__(self): return self.headline @@ -105,7 +109,7 @@ class Object(models.Model): @python_2_unicode_compatible class ObjectReference(models.Model): - obj = models.ForeignKey(Object, db_constraint=False) + obj = models.ForeignKey(Object, models.CASCADE, db_constraint=False) def __str__(self): return str(self.obj_id) diff --git a/tests/basic/models.py b/tests/basic/models.py index 86d0f0c4e4..0e85087d32 100644 --- a/tests/basic/models.py +++ b/tests/basic/models.py @@ -28,8 +28,12 @@ class ArticleSelectOnSave(Article): @python_2_unicode_compatible class SelfRef(models.Model): - selfref = models.ForeignKey('self', null=True, blank=True, - related_name='+') + selfref = models.ForeignKey( + 'self', + models.SET_NULL, + null=True, blank=True, + related_name='+', + ) def __str__(self): # This method intentionally doesn't work for all cases - part diff --git a/tests/check_framework/tests.py b/tests/check_framework/tests.py index 0b517aa5fe..a7cc9ad6fc 100644 --- a/tests/check_framework/tests.py +++ b/tests/check_framework/tests.py @@ -282,8 +282,12 @@ class CheckFrameworkReservedNamesTests(IsolateModelsMixin, SimpleTestCase): pass class ModelWithDescriptorCalledCheck(models.Model): - check = models.ForeignKey(ModelWithRelatedManagerCalledCheck) - article = models.ForeignKey(ModelWithRelatedManagerCalledCheck, related_name='check') + check = models.ForeignKey(ModelWithRelatedManagerCalledCheck, models.CASCADE) + article = models.ForeignKey( + ModelWithRelatedManagerCalledCheck, + models.CASCADE, + related_name='check', + ) errors = checks.run_checks() expected = [ diff --git a/tests/contenttypes_tests/models.py b/tests/contenttypes_tests/models.py index 15148cdebd..88b926fce6 100644 --- a/tests/contenttypes_tests/models.py +++ b/tests/contenttypes_tests/models.py @@ -20,7 +20,7 @@ class Author(models.Model): class Article(models.Model): title = models.CharField(max_length=100) slug = models.SlugField() - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) date_created = models.DateTimeField() def __str__(self): diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py index ef01a56301..3ff613d9c4 100644 --- a/tests/contenttypes_tests/tests.py +++ b/tests/contenttypes_tests/tests.py @@ -173,7 +173,7 @@ class GenericForeignKeyTests(IsolatedModelsTestCase): def test_content_type_field_pointing_to_wrong_model(self): class Model(models.Model): - content_type = models.ForeignKey('self') # should point to ContentType + content_type = models.ForeignKey('self', models.CASCADE) # should point to ContentType object_id = models.PositiveIntegerField() content_object = GenericForeignKey( 'content_type', 'object_id') @@ -191,7 +191,7 @@ class GenericForeignKeyTests(IsolatedModelsTestCase): def test_missing_object_id_field(self): class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) # missing object_id field content_object = GenericForeignKey() @@ -208,7 +208,7 @@ class GenericForeignKeyTests(IsolatedModelsTestCase): def test_field_name_ending_with_underscore(self): class Model(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object_ = GenericForeignKey( 'content_type', 'object_id') @@ -242,7 +242,7 @@ class GenericForeignKeyTests(IsolatedModelsTestCase): should raise an exception. """ class Model(models.Model): - content_type = models.ForeignKey(ContentType, null=True) + content_type = models.ForeignKey(ContentType, models.SET_NULL, null=True) object_id = models.PositiveIntegerField(null=True) content_object = GenericForeignKey('content_type', 'object_id') @@ -271,7 +271,7 @@ class GenericForeignKeyTests(IsolatedModelsTestCase): name = models.CharField(max_length=50) class BandMember(models.Model): - band_ct = models.ForeignKey(ContentType) + band_ct = models.ForeignKey(ContentType, models.CASCADE) band_id = models.PositiveIntegerField() band = UnsavedGenericForeignKey('band_ct', 'band_id') first_name = models.CharField(max_length=50) @@ -289,7 +289,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): def test_valid_generic_relationship(self): class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -301,7 +301,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): def test_valid_generic_relationship_with_explicit_fields(self): class TaggedItem(models.Model): - custom_content_type = models.ForeignKey(ContentType) + custom_content_type = models.ForeignKey(ContentType, models.CASCADE) custom_object_id = models.PositiveIntegerField() content_object = GenericForeignKey( 'custom_content_type', 'custom_object_id') @@ -333,7 +333,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): def test_valid_self_referential_generic_relationship(self): class Model(models.Model): rel = GenericRelation('Model') - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey( 'content_type', 'object_id') @@ -343,7 +343,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): def test_missing_generic_foreign_key(self): class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() class Bookmark(models.Model): @@ -368,7 +368,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): pass class SwappedModel(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -393,7 +393,7 @@ class GenericRelationshipTests(IsolatedModelsTestCase): def test_field_name_ending_with_underscore(self): class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() diff --git a/tests/custom_columns/models.py b/tests/custom_columns/models.py index a3e8b614aa..3f619a7f04 100644 --- a/tests/custom_columns/models.py +++ b/tests/custom_columns/models.py @@ -40,7 +40,13 @@ class Article(models.Model): Article_ID = models.AutoField(primary_key=True, db_column='Article ID') headline = models.CharField(max_length=100) authors = models.ManyToManyField(Author, db_table='my_m2m_table') - primary_author = models.ForeignKey(Author, db_column='Author ID', related_name='primary_set', null=True) + primary_author = models.ForeignKey( + Author, + models.SET_NULL, + db_column='Author ID', + related_name='primary_set', + null=True, + ) def __str__(self): return self.headline diff --git a/tests/custom_managers/models.py b/tests/custom_managers/models.py index 5607c11dd0..7fd50dc7f5 100644 --- a/tests/custom_managers/models.py +++ b/tests/custom_managers/models.py @@ -94,8 +94,8 @@ class Person(models.Model): last_name = models.CharField(max_length=30) fun = models.BooleanField(default=False) - favorite_book = models.ForeignKey('Book', null=True, related_name='favorite_books') - favorite_thing_type = models.ForeignKey('contenttypes.ContentType', null=True) + favorite_book = models.ForeignKey('Book', models.SET_NULL, null=True, related_name='favorite_books') + favorite_thing_type = models.ForeignKey('contenttypes.ContentType', models.SET_NULL, null=True) favorite_thing_id = models.IntegerField(null=True) favorite_thing = GenericForeignKey('favorite_thing_type', 'favorite_thing_id') @@ -117,8 +117,13 @@ class FunPerson(models.Model): last_name = models.CharField(max_length=30) fun = models.BooleanField(default=True) - favorite_book = models.ForeignKey('Book', null=True, related_name='fun_people_favorite_books') - favorite_thing_type = models.ForeignKey('contenttypes.ContentType', null=True) + favorite_book = models.ForeignKey( + 'Book', + models.SET_NULL, + null=True, + related_name='fun_people_favorite_books', + ) + favorite_thing_type = models.ForeignKey('contenttypes.ContentType', models.SET_NULL, null=True) favorite_thing_id = models.IntegerField(null=True) favorite_thing = GenericForeignKey('favorite_thing_type', 'favorite_thing_id') @@ -181,7 +186,7 @@ class RelatedModel(models.Model): class RestrictedModel(models.Model): name = models.CharField(max_length=50) is_public = models.BooleanField(default=False) - related = models.ForeignKey(RelatedModel) + related = models.ForeignKey(RelatedModel, models.CASCADE) objects = RestrictedManager() plain_manager = models.Manager() @@ -194,7 +199,7 @@ class RestrictedModel(models.Model): class OneToOneRestrictedModel(models.Model): name = models.CharField(max_length=50) is_public = models.BooleanField(default=False) - related = models.OneToOneField(RelatedModel) + related = models.OneToOneField(RelatedModel, models.CASCADE) objects = RestrictedManager() plain_manager = models.Manager() diff --git a/tests/custom_pk/models.py b/tests/custom_pk/models.py index eb9f86b064..20b484c426 100644 --- a/tests/custom_pk/models.py +++ b/tests/custom_pk/models.py @@ -48,4 +48,4 @@ class Bar(models.Model): class Foo(models.Model): - bar = models.ForeignKey(Bar) + bar = models.ForeignKey(Bar, models.CASCADE) diff --git a/tests/dates/models.py b/tests/dates/models.py index d27c22ff67..58e6d10d91 100644 --- a/tests/dates/models.py +++ b/tests/dates/models.py @@ -17,7 +17,7 @@ class Article(models.Model): @python_2_unicode_compatible class Comment(models.Model): - article = models.ForeignKey(Article, related_name="comments") + article = models.ForeignKey(Article, models.CASCADE, related_name="comments") text = models.TextField() pub_date = models.DateField() approval_date = models.DateField(null=True) diff --git a/tests/datetimes/models.py b/tests/datetimes/models.py index cfdd521b53..47ce417e4c 100644 --- a/tests/datetimes/models.py +++ b/tests/datetimes/models.py @@ -17,7 +17,7 @@ class Article(models.Model): @python_2_unicode_compatible class Comment(models.Model): - article = models.ForeignKey(Article, related_name="comments") + article = models.ForeignKey(Article, models.CASCADE, related_name="comments") text = models.TextField() pub_date = models.DateTimeField() approval_date = models.DateTimeField(null=True) diff --git a/tests/db_functions/models.py b/tests/db_functions/models.py index f100b79ff5..788fe01b9f 100644 --- a/tests/db_functions/models.py +++ b/tests/db_functions/models.py @@ -37,7 +37,7 @@ class Article(models.Model): class Fan(models.Model): name = models.CharField(max_length=50) age = models.PositiveSmallIntegerField(default=30) - author = models.ForeignKey(Author, related_name='fans') + author = models.ForeignKey(Author, models.CASCADE, related_name='fans') def __str__(self): return self.name diff --git a/tests/defer/models.py b/tests/defer/models.py index ecf69c0d7f..b36b173501 100644 --- a/tests/defer/models.py +++ b/tests/defer/models.py @@ -15,7 +15,7 @@ class Secondary(models.Model): class Primary(models.Model): name = models.CharField(max_length=50) value = models.CharField(max_length=50) - related = models.ForeignKey(Secondary) + related = models.ForeignKey(Secondary, models.CASCADE) def __str__(self): return self.name diff --git a/tests/defer_regress/models.py b/tests/defer_regress/models.py index a81b02058d..a73f539ba1 100644 --- a/tests/defer_regress/models.py +++ b/tests/defer_regress/models.py @@ -18,7 +18,7 @@ class Item(models.Model): class RelatedItem(models.Model): - item = models.ForeignKey(Item) + item = models.ForeignKey(Item, models.CASCADE) class ProxyRelated(RelatedItem): @@ -34,8 +34,8 @@ class Child(models.Model): @python_2_unicode_compatible class Leaf(models.Model): name = models.CharField(max_length=10) - child = models.ForeignKey(Child) - second_child = models.ForeignKey(Child, related_name="other", null=True) + child = models.ForeignKey(Child, models.CASCADE) + second_child = models.ForeignKey(Child, models.SET_NULL, related_name="other", null=True) value = models.IntegerField(default=42) def __str__(self): @@ -62,21 +62,21 @@ class SimpleItem(models.Model): class Feature(models.Model): - item = models.ForeignKey(SimpleItem) + item = models.ForeignKey(SimpleItem, models.CASCADE) class SpecialFeature(models.Model): - feature = models.ForeignKey(Feature) + feature = models.ForeignKey(Feature, models.CASCADE) class OneToOneItem(models.Model): - item = models.OneToOneField(Item, related_name="one_to_one_item") + item = models.OneToOneField(Item, models.CASCADE, related_name="one_to_one_item") name = models.CharField(max_length=15) class ItemAndSimpleItem(models.Model): - item = models.ForeignKey(Item) - simple = models.ForeignKey(SimpleItem) + item = models.ForeignKey(Item, models.CASCADE) + simple = models.ForeignKey(SimpleItem, models.CASCADE) class Profile(models.Model): @@ -88,8 +88,8 @@ class Location(models.Model): class Request(models.Model): - profile = models.ForeignKey(Profile, null=True, blank=True) - location = models.ForeignKey(Location) + profile = models.ForeignKey(Profile, models.SET_NULL, null=True, blank=True) + location = models.ForeignKey(Location, models.CASCADE) items = models.ManyToManyField(Item) request1 = models.CharField(default='request1', max_length=1000) diff --git a/tests/delete/models.py b/tests/delete/models.py index 3255c68c64..a7838c4510 100644 --- a/tests/delete/models.py +++ b/tests/delete/models.py @@ -17,15 +17,15 @@ def get_default_r(): class S(models.Model): - r = models.ForeignKey(R) + r = models.ForeignKey(R, models.CASCADE) class T(models.Model): - s = models.ForeignKey(S) + s = models.ForeignKey(S, models.CASCADE) class U(models.Model): - t = models.ForeignKey(T) + t = models.ForeignKey(T, models.CASCADE) class RChild(R): @@ -35,33 +35,33 @@ class RChild(R): class A(models.Model): name = models.CharField(max_length=30) - auto = models.ForeignKey(R, related_name="auto_set") - auto_nullable = models.ForeignKey(R, null=True, + auto = models.ForeignKey(R, models.CASCADE, related_name="auto_set") + auto_nullable = models.ForeignKey(R, models.CASCADE, null=True, related_name='auto_nullable_set') - setvalue = models.ForeignKey(R, on_delete=models.SET(get_default_r), + setvalue = models.ForeignKey(R, models.SET(get_default_r), related_name='setvalue') - setnull = models.ForeignKey(R, on_delete=models.SET_NULL, null=True, + setnull = models.ForeignKey(R, models.SET_NULL, null=True, related_name='setnull_set') - setdefault = models.ForeignKey(R, on_delete=models.SET_DEFAULT, + setdefault = models.ForeignKey(R, models.SET_DEFAULT, default=get_default_r, related_name='setdefault_set') - setdefault_none = models.ForeignKey(R, on_delete=models.SET_DEFAULT, + setdefault_none = models.ForeignKey(R, models.SET_DEFAULT, default=None, null=True, related_name='setnull_nullable_set') - cascade = models.ForeignKey(R, on_delete=models.CASCADE, + cascade = models.ForeignKey(R, models.CASCADE, related_name='cascade_set') - cascade_nullable = models.ForeignKey(R, on_delete=models.CASCADE, null=True, + cascade_nullable = models.ForeignKey(R, models.CASCADE, null=True, related_name='cascade_nullable_set') - protect = models.ForeignKey(R, on_delete=models.PROTECT, null=True) - donothing = models.ForeignKey(R, on_delete=models.DO_NOTHING, null=True, + protect = models.ForeignKey(R, models.PROTECT, null=True) + donothing = models.ForeignKey(R, models.DO_NOTHING, null=True, related_name='donothing_set') - child = models.ForeignKey(RChild, related_name="child") - child_setnull = models.ForeignKey(RChild, on_delete=models.SET_NULL, null=True, + child = models.ForeignKey(RChild, models.CASCADE, related_name="child") + child_setnull = models.ForeignKey(RChild, models.SET_NULL, null=True, related_name="child_setnull") # A OneToOneField is just a ForeignKey unique=True, so we don't duplicate # all the tests; just one smoke test to ensure on_delete works for it as # well. - o2o_setnull = models.ForeignKey(R, null=True, - on_delete=models.SET_NULL, related_name="o2o_nullable_set") + o2o_setnull = models.ForeignKey(R, models.SET_NULL, null=True, + related_name="o2o_nullable_set") def create_a(name): @@ -86,13 +86,13 @@ class M(models.Model): class MR(models.Model): - m = models.ForeignKey(M) - r = models.ForeignKey(R) + m = models.ForeignKey(M, models.CASCADE) + r = models.ForeignKey(R, models.CASCADE) class MRNull(models.Model): - m = models.ForeignKey(M) - r = models.ForeignKey(R, null=True, on_delete=models.SET_NULL) + m = models.ForeignKey(M, models.CASCADE) + r = models.ForeignKey(R, models.SET_NULL, null=True) class Avatar(models.Model): @@ -100,15 +100,15 @@ class Avatar(models.Model): class User(models.Model): - avatar = models.ForeignKey(Avatar, null=True) + avatar = models.ForeignKey(Avatar, models.CASCADE, null=True) class HiddenUser(models.Model): - r = models.ForeignKey(R, related_name="+") + r = models.ForeignKey(R, models.CASCADE, related_name="+") class HiddenUserProfile(models.Model): - user = models.ForeignKey(HiddenUser) + user = models.ForeignKey(HiddenUser, models.CASCADE) class M2MTo(models.Model): @@ -132,4 +132,4 @@ class Base(models.Model): class RelToBase(models.Model): - base = models.ForeignKey(Base, on_delete=models.DO_NOTHING) + base = models.ForeignKey(Base, models.DO_NOTHING) diff --git a/tests/delete_regress/models.py b/tests/delete_regress/models.py index c3ecdac7bf..f0145de65b 100644 --- a/tests/delete_regress/models.py +++ b/tests/delete_regress/models.py @@ -8,12 +8,12 @@ from django.db import models class Award(models.Model): name = models.CharField(max_length=25) object_id = models.PositiveIntegerField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) content_object = GenericForeignKey() class AwardNote(models.Model): - award = models.ForeignKey(Award) + award = models.ForeignKey(Award, models.CASCADE) note = models.CharField(max_length=100) @@ -36,13 +36,13 @@ class Child(models.Model): class PlayedWith(models.Model): - child = models.ForeignKey(Child) - toy = models.ForeignKey(Toy) + child = models.ForeignKey(Child, models.CASCADE) + toy = models.ForeignKey(Toy, models.CASCADE) date = models.DateField(db_column='date_col') class PlayedWithNote(models.Model): - played = models.ForeignKey(PlayedWith) + played = models.ForeignKey(PlayedWith, models.CASCADE) note = models.TextField() @@ -63,7 +63,7 @@ class Food(models.Model): class Eaten(models.Model): - food = models.ForeignKey(Food, to_field="name") + food = models.ForeignKey(Food, models.CASCADE, to_field="name") meal = models.CharField(max_length=20) @@ -75,16 +75,16 @@ class Policy(models.Model): class Version(models.Model): - policy = models.ForeignKey(Policy) + policy = models.ForeignKey(Policy, models.CASCADE) class Location(models.Model): - version = models.ForeignKey(Version, blank=True, null=True) + version = models.ForeignKey(Version, models.SET_NULL, blank=True, null=True) class Item(models.Model): - version = models.ForeignKey(Version) - location = models.ForeignKey(Location, blank=True, null=True) + version = models.ForeignKey(Version, models.CASCADE) + location = models.ForeignKey(Location, models.SET_NULL, blank=True, null=True) # Models for #16128 @@ -104,15 +104,15 @@ class Photo(Image): class FooImage(models.Model): - my_image = models.ForeignKey(Image) + my_image = models.ForeignKey(Image, models.CASCADE) class FooFile(models.Model): - my_file = models.ForeignKey(File) + my_file = models.ForeignKey(File, models.CASCADE) class FooPhoto(models.Model): - my_photo = models.ForeignKey(Photo) + my_photo = models.ForeignKey(Photo, models.CASCADE) class FooFileProxy(FooFile): @@ -126,7 +126,7 @@ class OrgUnit(models.Model): class Login(models.Model): description = models.CharField(max_length=32) - orgunit = models.ForeignKey(OrgUnit) + orgunit = models.ForeignKey(OrgUnit, models.CASCADE) class House(models.Model): @@ -135,7 +135,7 @@ class House(models.Model): class OrderedPerson(models.Model): name = models.CharField(max_length=32) - lives_in = models.ForeignKey(House) + lives_in = models.ForeignKey(House, models.CASCADE) class Meta: ordering = ['name'] diff --git a/tests/distinct_on_fields/models.py b/tests/distinct_on_fields/models.py index 053fd9cc5f..2c33f3ad80 100644 --- a/tests/distinct_on_fields/models.py +++ b/tests/distinct_on_fields/models.py @@ -7,8 +7,13 @@ from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class Tag(models.Model): name = models.CharField(max_length=10) - parent = models.ForeignKey('self', blank=True, null=True, - related_name='children') + parent = models.ForeignKey( + 'self', + models.SET_NULL, + blank=True, + null=True, + related_name='children', + ) class Meta: ordering = ['name'] @@ -20,14 +25,19 @@ class Tag(models.Model): @python_2_unicode_compatible class Celebrity(models.Model): name = models.CharField("Name", max_length=20) - greatest_fan = models.ForeignKey("Fan", null=True, unique=True) + greatest_fan = models.ForeignKey( + "Fan", + models.SET_NULL, + null=True, + unique=True, + ) def __str__(self): return self.name class Fan(models.Model): - fan_of = models.ForeignKey(Celebrity) + fan_of = models.ForeignKey(Celebrity, models.CASCADE) @python_2_unicode_compatible @@ -44,8 +54,8 @@ class Staff(models.Model): @python_2_unicode_compatible class StaffTag(models.Model): - staff = models.ForeignKey(Staff) - tag = models.ForeignKey(Tag) + staff = models.ForeignKey(Staff, models.CASCADE) + tag = models.ForeignKey(Tag, models.CASCADE) def __str__(self): return "%s -> %s" % (self.tag, self.staff) diff --git a/tests/expressions/models.py b/tests/expressions/models.py index 1c1e924079..4633008868 100644 --- a/tests/expressions/models.py +++ b/tests/expressions/models.py @@ -25,9 +25,11 @@ class Company(models.Model): num_chairs = models.PositiveIntegerField() ceo = models.ForeignKey( Employee, + models.CASCADE, related_name='company_ceo_set') point_of_contact = models.ForeignKey( Employee, + models.SET_NULL, related_name='company_point_of_contact_set', null=True) diff --git a/tests/expressions_case/models.py b/tests/expressions_case/models.py index 1a35d544e7..1471239896 100644 --- a/tests/expressions_case/models.py +++ b/tests/expressions_case/models.py @@ -39,7 +39,7 @@ class CaseTestModel(models.Model): time = models.TimeField(null=True, db_column='time_field') url = models.URLField(default='') uuid = models.UUIDField(null=True) - fk = models.ForeignKey('self', null=True) + fk = models.ForeignKey('self', models.CASCADE, null=True) def __str__(self): return "%i, %s" % (self.integer, self.string) @@ -47,7 +47,7 @@ class CaseTestModel(models.Model): @python_2_unicode_compatible class O2OCaseTestModel(models.Model): - o2o = models.OneToOneField(CaseTestModel, related_name='o2o_rel') + o2o = models.OneToOneField(CaseTestModel, models.CASCADE, related_name='o2o_rel') integer = models.IntegerField() def __str__(self): @@ -56,7 +56,7 @@ class O2OCaseTestModel(models.Model): @python_2_unicode_compatible class FKCaseTestModel(models.Model): - fk = models.ForeignKey(CaseTestModel, related_name='fk_rel') + fk = models.ForeignKey(CaseTestModel, models.CASCADE, related_name='fk_rel') integer = models.IntegerField() def __str__(self): diff --git a/tests/extra_regress/models.py b/tests/extra_regress/models.py index 432aa02963..893c32ddd6 100644 --- a/tests/extra_regress/models.py +++ b/tests/extra_regress/models.py @@ -10,7 +10,7 @@ from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class RevisionableModel(models.Model): - base = models.ForeignKey('self', null=True) + base = models.ForeignKey('self', models.SET_NULL, null=True) title = models.CharField(blank=True, max_length=255) when = models.DateTimeField(default=datetime.datetime.now) @@ -32,7 +32,7 @@ class RevisionableModel(models.Model): class Order(models.Model): - created_by = models.ForeignKey(User) + created_by = models.ForeignKey(User, models.CASCADE) text = models.TextField() diff --git a/tests/field_deconstruction/tests.py b/tests/field_deconstruction/tests.py index 6a0fe114ce..c1cc083fc5 100644 --- a/tests/field_deconstruction/tests.py +++ b/tests/field_deconstruction/tests.py @@ -23,7 +23,7 @@ class FieldDeconstructionTests(SimpleTestCase): self.assertEqual(name, "is_awesome_test") self.assertIsInstance(name, six.text_type) # Now try with a ForeignKey - field = models.ForeignKey("some_fake.ModelName") + field = models.ForeignKey("some_fake.ModelName", models.CASCADE) name, path, args, kwargs = field.deconstruct() self.assertIsNone(name) field.set_attributes_from_name("author") @@ -177,55 +177,55 @@ class FieldDeconstructionTests(SimpleTestCase): def test_foreign_key(self): # Test basic pointing from django.contrib.auth.models import Permission - field = models.ForeignKey("auth.Permission") + field = models.ForeignKey("auth.Permission", models.CASCADE) field.remote_field.model = Permission field.remote_field.field_name = "id" name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "auth.Permission"}) + self.assertEqual(kwargs, {"to": "auth.Permission", "on_delete": models.CASCADE}) self.assertFalse(hasattr(kwargs['to'], "setting_name")) # Test swap detection for swappable model - field = models.ForeignKey("auth.User") + field = models.ForeignKey("auth.User", models.CASCADE) name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "auth.User"}) + self.assertEqual(kwargs, {"to": "auth.User", "on_delete": models.CASCADE}) self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL") # Test nonexistent (for now) model - field = models.ForeignKey("something.Else") + field = models.ForeignKey("something.Else", models.CASCADE) name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "something.Else"}) + self.assertEqual(kwargs, {"to": "something.Else", "on_delete": models.CASCADE}) # Test on_delete - field = models.ForeignKey("auth.User", on_delete=models.SET_NULL) + field = models.ForeignKey("auth.User", models.SET_NULL) name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) self.assertEqual(kwargs, {"to": "auth.User", "on_delete": models.SET_NULL}) # Test to_field preservation - field = models.ForeignKey("auth.Permission", to_field="foobar") + field = models.ForeignKey("auth.Permission", models.CASCADE, to_field="foobar") name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "auth.Permission", "to_field": "foobar"}) + self.assertEqual(kwargs, {"to": "auth.Permission", "to_field": "foobar", "on_delete": models.CASCADE}) # Test related_name preservation - field = models.ForeignKey("auth.Permission", related_name="foobar") + field = models.ForeignKey("auth.Permission", models.CASCADE, related_name="foobar") name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "auth.Permission", "related_name": "foobar"}) + self.assertEqual(kwargs, {"to": "auth.Permission", "related_name": "foobar", "on_delete": models.CASCADE}) @override_settings(AUTH_USER_MODEL="auth.Permission") def test_foreign_key_swapped(self): # It doesn't matter that we swapped out user for permission; # there's no validation. We just want to check the setting stuff works. - field = models.ForeignKey("auth.Permission") + field = models.ForeignKey("auth.Permission", models.CASCADE) name, path, args, kwargs = field.deconstruct() self.assertEqual(path, "django.db.models.ForeignKey") self.assertEqual(args, []) - self.assertEqual(kwargs, {"to": "auth.Permission"}) + self.assertEqual(kwargs, {"to": "auth.Permission", "on_delete": models.CASCADE}) self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL") def test_image_field(self): diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py index faa09f8eff..391e030f8c 100644 --- a/tests/fixtures/models.py +++ b/tests/fixtures/models.py @@ -42,7 +42,7 @@ class Article(models.Model): @python_2_unicode_compatible class Blog(models.Model): name = models.CharField(max_length=100) - featured = models.ForeignKey(Article, related_name='fixtures_featured_set') + featured = models.ForeignKey(Article, models.CASCADE, related_name='fixtures_featured_set') articles = models.ManyToManyField(Article, blank=True, related_name='fixtures_articles_set') @@ -53,7 +53,7 @@ class Blog(models.Model): @python_2_unicode_compatible class Tag(models.Model): name = models.CharField(max_length=100) - tagged_type = models.ForeignKey(ContentType, related_name="fixtures_tag_set") + tagged_type = models.ForeignKey(ContentType, models.CASCADE, related_name="fixtures_tag_set") tagged_id = models.PositiveIntegerField(default=0) tagged = GenericForeignKey(ct_field='tagged_type', fk_field='tagged_id') @@ -94,7 +94,7 @@ class Spy(Person): @python_2_unicode_compatible class Visa(models.Model): - person = models.ForeignKey(Person) + person = models.ForeignKey(Person, models.CASCADE) permissions = models.ManyToManyField(Permission, blank=True) def __str__(self): diff --git a/tests/fixtures_regress/models.py b/tests/fixtures_regress/models.py index 48a462ae6d..084b602b7c 100644 --- a/tests/fixtures_regress/models.py +++ b/tests/fixtures_regress/models.py @@ -31,7 +31,7 @@ class Plant(models.Model): @python_2_unicode_compatible class Stuff(models.Model): name = models.CharField(max_length=20, null=True) - owner = models.ForeignKey(User, null=True) + owner = models.ForeignKey(User, models.SET_NULL, null=True) def __str__(self): return six.text_type(self.name) + ' is owned by ' + six.text_type(self.owner) @@ -108,7 +108,7 @@ class TestManager(models.Manager): class Store(models.Model): objects = TestManager() name = models.CharField(max_length=255) - main = models.ForeignKey('self', null=True) + main = models.ForeignKey('self', models.SET_NULL, null=True) class Meta: ordering = ('name',) @@ -141,7 +141,7 @@ class Person(models.Model): @python_2_unicode_compatible class Book(models.Model): name = models.CharField(max_length=255) - author = models.ForeignKey(Person) + author = models.ForeignKey(Person, models.CASCADE) stores = models.ManyToManyField(Store) class Meta: @@ -175,7 +175,7 @@ class NKChild(Parent): @python_2_unicode_compatible class RefToNKChild(models.Model): text = models.CharField(max_length=10) - nk_fk = models.ForeignKey(NKChild, related_name='ref_fks') + nk_fk = models.ForeignKey(NKChild, models.CASCADE, related_name='ref_fks') nk_m2m = models.ManyToManyField(NKChild, related_name='ref_m2ms') def __str__(self): @@ -295,8 +295,8 @@ class M2MComplexB(BaseNKModel): class M2MThroughAB(BaseNKModel): - a = models.ForeignKey(M2MComplexA) - b = models.ForeignKey(M2MComplexB) + a = models.ForeignKey(M2MComplexA, models.CASCADE) + b = models.ForeignKey(M2MComplexB, models.CASCADE) class M2MComplexCircular1A(BaseNKModel): @@ -315,18 +315,18 @@ class M2MComplexCircular1C(BaseNKModel): class M2MCircular1ThroughAB(BaseNKModel): - a = models.ForeignKey(M2MComplexCircular1A) - b = models.ForeignKey(M2MComplexCircular1B) + a = models.ForeignKey(M2MComplexCircular1A, models.CASCADE) + b = models.ForeignKey(M2MComplexCircular1B, models.CASCADE) class M2MCircular1ThroughBC(BaseNKModel): - b = models.ForeignKey(M2MComplexCircular1B) - c = models.ForeignKey(M2MComplexCircular1C) + b = models.ForeignKey(M2MComplexCircular1B, models.CASCADE) + c = models.ForeignKey(M2MComplexCircular1C, models.CASCADE) class M2MCircular1ThroughCA(BaseNKModel): - c = models.ForeignKey(M2MComplexCircular1C) - a = models.ForeignKey(M2MComplexCircular1A) + c = models.ForeignKey(M2MComplexCircular1C, models.CASCADE) + a = models.ForeignKey(M2MComplexCircular1A, models.CASCADE) class M2MComplexCircular2A(BaseNKModel): @@ -342,5 +342,5 @@ class M2MComplexCircular2B(BaseNKModel): class M2MCircular2ThroughAB(BaseNKModel): - a = models.ForeignKey(M2MComplexCircular2A) - b = models.ForeignKey(M2MComplexCircular2B) + a = models.ForeignKey(M2MComplexCircular2A, models.CASCADE) + b = models.ForeignKey(M2MComplexCircular2B, models.CASCADE) diff --git a/tests/foreign_object/models.py b/tests/foreign_object/models.py index 177a200758..4d47877763 100644 --- a/tests/foreign_object/models.py +++ b/tests/foreign_object/models.py @@ -24,7 +24,11 @@ class Person(models.Model): # Relation Fields person_country = models.ForeignObject( - Country, from_fields=['person_country_id'], to_fields=['id']) + Country, + from_fields=['person_country_id'], + to_fields=['id'], + on_delete=models.CASCADE, + ) friends = models.ManyToManyField('self', through='Friendship', symmetrical=False) class Meta: @@ -38,7 +42,7 @@ class Person(models.Model): class Group(models.Model): # Table Column Fields name = models.CharField(max_length=128) - group_country = models.ForeignKey(Country) + group_country = models.ForeignKey(Country, models.CASCADE) members = models.ManyToManyField(Person, related_name='groups', through='Membership') class Meta: @@ -51,7 +55,7 @@ class Group(models.Model): @python_2_unicode_compatible class Membership(models.Model): # Table Column Fields - membership_country = models.ForeignKey(Country) + membership_country = models.ForeignKey(Country, models.CASCADE) date_joined = models.DateTimeField(default=datetime.datetime.now) invite_reason = models.CharField(max_length=64, null=True) person_id = models.IntegerField() @@ -61,11 +65,15 @@ class Membership(models.Model): person = models.ForeignObject( Person, from_fields=['membership_country', 'person_id'], - to_fields=['person_country_id', 'id']) + to_fields=['person_country_id', 'id'], + on_delete=models.CASCADE, + ) group = models.ForeignObject( Group, from_fields=['membership_country', 'group_id'], - to_fields=['group_country', 'id']) + to_fields=['group_country', 'id'], + on_delete=models.CASCADE, + ) class Meta: ordering = ('date_joined', 'invite_reason') @@ -76,7 +84,7 @@ class Membership(models.Model): class Friendship(models.Model): # Table Column Fields - from_friend_country = models.ForeignKey(Country, related_name="from_friend_country") + from_friend_country = models.ForeignKey(Country, models.CASCADE, related_name="from_friend_country") from_friend_id = models.IntegerField() to_friend_country_id = models.IntegerField() to_friend_id = models.IntegerField() @@ -84,6 +92,7 @@ class Friendship(models.Model): # Relation Fields from_friend = models.ForeignObject( Person, + on_delete=models.CASCADE, from_fields=['from_friend_country', 'from_friend_id'], to_fields=['person_country_id', 'id'], related_name='from_friend') @@ -92,13 +101,17 @@ class Friendship(models.Model): Country, from_fields=['to_friend_country_id'], to_fields=['id'], - related_name='to_friend_country') + related_name='to_friend_country', + on_delete=models.CASCADE, + ) to_friend = models.ForeignObject( Person, from_fields=['to_friend_country_id', 'to_friend_id'], to_fields=['person_country_id', 'id'], - related_name='to_friend') + related_name='to_friend', + on_delete=models.CASCADE, + ) class ArticleTranslationDescriptor(ReverseSingleRelatedObjectDescriptor): @@ -148,7 +161,9 @@ class Article(models.Model): from_fields=['id'], to_fields=['article'], related_name='+', - null=True) + on_delete=models.CASCADE, + null=True, + ) pub_date = models.DateField() def __str__(self): @@ -163,7 +178,7 @@ class NewsArticle(Article): class ArticleTranslation(models.Model): - article = models.ForeignKey(Article) + article = models.ForeignKey(Article, models.CASCADE) lang = models.CharField(max_length=2) title = models.CharField(max_length=100) body = models.TextField() @@ -175,7 +190,7 @@ class ArticleTranslation(models.Model): class ArticleTag(models.Model): - article = models.ForeignKey(Article, related_name="tags", related_query_name="tag") + article = models.ForeignKey(Article, models.CASCADE, related_name="tags", related_query_name="tag") name = models.CharField(max_length=255) diff --git a/tests/forms_tests/models.py b/tests/forms_tests/models.py index d7e9d583ff..511a3d0d44 100644 --- a/tests/forms_tests/models.py +++ b/tests/forms_tests/models.py @@ -92,11 +92,13 @@ class ChoiceFieldModel(models.Model): generation with ModelChoiceField.""" choice = models.ForeignKey( ChoiceOptionModel, + models.CASCADE, blank=False, default=choice_default, ) choice_int = models.ForeignKey( ChoiceOptionModel, + models.CASCADE, blank=False, related_name='choice_int', default=int_default, diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py index 211866b2f1..b81053c6cb 100644 --- a/tests/forms_tests/tests/tests.py +++ b/tests/forms_tests/tests/tests.py @@ -228,7 +228,7 @@ class RelatedModelFormTests(SimpleTestCase): Test for issue 10405 """ class A(models.Model): - ref = models.ForeignKey("B") + ref = models.ForeignKey("B", models.CASCADE) class Meta: model = A @@ -244,7 +244,7 @@ class RelatedModelFormTests(SimpleTestCase): Test for issue 10405 """ class C(models.Model): - ref = models.ForeignKey("D") + ref = models.ForeignKey("D", models.CASCADE) class D(models.Model): pass diff --git a/tests/generic_inline_admin/models.py b/tests/generic_inline_admin/models.py index 491536be58..e981612bd8 100644 --- a/tests/generic_inline_admin/models.py +++ b/tests/generic_inline_admin/models.py @@ -17,7 +17,7 @@ class Media(models.Model): """ Media that can associated to any object. """ - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() url = models.URLField() @@ -36,11 +36,11 @@ class Category(models.Model): class PhoneNumber(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') phone_number = models.CharField(max_length=30) - category = models.ForeignKey(Category, null=True, blank=True) + category = models.ForeignKey(Category, models.SET_NULL, null=True, blank=True) class Meta: unique_together = (('content_type', 'object_id', 'phone_number',),) diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py index 1f1872dd0f..4b42354d99 100644 --- a/tests/generic_relations/models.py +++ b/tests/generic_relations/models.py @@ -23,7 +23,7 @@ from django.utils.encoding import python_2_unicode_compatible class TaggedItem(models.Model): """A tag on an item.""" tag = models.SlugField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -42,7 +42,7 @@ class ValuableTaggedItem(TaggedItem): class AbstractComparison(models.Model): comparative = models.CharField(max_length=50) - content_type1 = models.ForeignKey(ContentType, related_name="comparative1_set") + content_type1 = models.ForeignKey(ContentType, models.CASCADE, related_name="comparative1_set") object_id1 = models.PositiveIntegerField() first_obj = GenericForeignKey(ct_field="content_type1", fk_field="object_id1") @@ -54,7 +54,7 @@ class Comparison(AbstractComparison): A model that tests having multiple GenericForeignKeys. One is defined through an inherited abstract model and one defined directly on this class. """ - content_type2 = models.ForeignKey(ContentType, related_name="comparative2_set") + content_type2 = models.ForeignKey(ContentType, models.CASCADE, related_name="comparative2_set") object_id2 = models.PositiveIntegerField() other_obj = GenericForeignKey(ct_field="content_type2", fk_field="object_id2") @@ -120,14 +120,14 @@ class ManualPK(models.Model): class ForProxyModelModel(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() obj = GenericForeignKey(for_concrete_model=False) title = models.CharField(max_length=255, null=True) class ForConcreteModelModel(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() obj = GenericForeignKey() @@ -143,6 +143,6 @@ class ProxyRelatedModel(ConcreteRelatedModel): # To test fix for #7551 class AllowsNullGFK(models.Model): - content_type = models.ForeignKey(ContentType, null=True) + content_type = models.ForeignKey(ContentType, models.SET_NULL, null=True) object_id = models.PositiveIntegerField(null=True) content_object = GenericForeignKey() diff --git a/tests/generic_relations_regress/models.py b/tests/generic_relations_regress/models.py index ffedbc86f8..331c5751a1 100644 --- a/tests/generic_relations_regress/models.py +++ b/tests/generic_relations_regress/models.py @@ -13,7 +13,7 @@ __all__ = ('Link', 'Place', 'Restaurant', 'Person', 'Address', @python_2_unicode_compatible class Link(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -42,7 +42,7 @@ class Address(models.Model): city = models.CharField(max_length=50) state = models.CharField(max_length=2) zipcode = models.CharField(max_length=5) - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -61,13 +61,13 @@ class Person(models.Model): class CharLink(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.CharField(max_length=100) content_object = GenericForeignKey() class TextLink(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.TextField() content_object = GenericForeignKey() @@ -84,7 +84,7 @@ class OddRelation2(models.Model): # models for test_q_object_or: class Note(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() note = models.TextField() @@ -135,7 +135,7 @@ class Guild(models.Model): class Tag(models.Model): - content_type = models.ForeignKey(ContentType, related_name='g_r_r_tags') + content_type = models.ForeignKey(ContentType, models.CASCADE, related_name='g_r_r_tags') object_id = models.CharField(max_length=15) content_object = GenericForeignKey() label = models.CharField(max_length=15) @@ -168,7 +168,7 @@ class HasLinkThing(HasLinks): class A(models.Model): flag = models.NullBooleanField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') @@ -181,14 +181,14 @@ class B(models.Model): class C(models.Model): - b = models.ForeignKey(B) + b = models.ForeignKey(B, models.CASCADE) class Meta: ordering = ('id',) class D(models.Model): - b = models.ForeignKey(B, null=True) + b = models.ForeignKey(B, models.SET_NULL, null=True) class Meta: ordering = ('id',) @@ -197,14 +197,14 @@ class D(models.Model): # Ticket #22998 class Node(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content = GenericForeignKey('content_type', 'object_id') class Content(models.Model): nodes = GenericRelation(Node) - related_obj = models.ForeignKey('Related', on_delete=models.CASCADE) + related_obj = models.ForeignKey('Related', models.CASCADE) class Related(models.Model): diff --git a/tests/get_or_create/models.py b/tests/get_or_create/models.py index 44e9967501..0394434408 100644 --- a/tests/get_or_create/models.py +++ b/tests/get_or_create/models.py @@ -25,7 +25,7 @@ class ManualPrimaryKeyTest(models.Model): class Profile(models.Model): - person = models.ForeignKey(Person, primary_key=True) + person = models.ForeignKey(Person, models.CASCADE, primary_key=True) class Tag(models.Model): @@ -48,4 +48,9 @@ class Author(models.Model): class Book(models.Model): name = models.CharField(max_length=100) authors = models.ManyToManyField(Author, related_name='books') - publisher = models.ForeignKey(Publisher, related_name='books', db_column="publisher_id_column") + publisher = models.ForeignKey( + Publisher, + models.CASCADE, + related_name='books', + db_column="publisher_id_column", + ) diff --git a/tests/gis_tests/geoapp/models.py b/tests/gis_tests/geoapp/models.py index 2349b29659..664aac9d7b 100644 --- a/tests/gis_tests/geoapp/models.py +++ b/tests/gis_tests/geoapp/models.py @@ -57,7 +57,7 @@ class Track(NamedModel): class MultiFields(NamedModel): - city = models.ForeignKey(City) + city = models.ForeignKey(City, models.CASCADE) point = models.PointField() poly = models.PolygonField() diff --git a/tests/gis_tests/gis_migrations/migrations/0001_initial.py b/tests/gis_tests/gis_migrations/migrations/0001_initial.py index 6615fdf2c4..e4545dc8aa 100644 --- a/tests/gis_tests/gis_migrations/migrations/0001_initial.py +++ b/tests/gis_tests/gis_migrations/migrations/0001_initial.py @@ -19,7 +19,12 @@ ops = [ name='Household', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('neighborhood', models.ForeignKey(to='gis_migrations.Neighborhood', to_field='id', null=True)), + ('neighborhood', models.ForeignKey( + 'gis_migrations.Neighborhood', + models.SET_NULL, + to_field='id', + null=True, + )), ('address', models.CharField(max_length=100)), ('zip_code', models.IntegerField(null=True, blank=True)), ('geom', gis_models.PointField(srid=4326, geography=True)), @@ -42,7 +47,7 @@ ops = [ migrations.AddField( model_name='household', name='family', - field=models.ForeignKey(blank=True, to='gis_migrations.Family', null=True), + field=models.ForeignKey('gis_migrations.Family', models.SET_NULL, blank=True, null=True), preserve_default=True, ) ] diff --git a/tests/gis_tests/layermap/models.py b/tests/gis_tests/layermap/models.py index 4ffcad0486..3457e0e2d5 100644 --- a/tests/gis_tests/layermap/models.py +++ b/tests/gis_tests/layermap/models.py @@ -22,7 +22,7 @@ class State(NamedModel): class County(NamedModel): - state = models.ForeignKey(State) + state = models.ForeignKey(State, models.CASCADE) mpoly = models.MultiPolygonField(srid=4269) # Multipolygon in NAD83 diff --git a/tests/gis_tests/relatedapp/models.py b/tests/gis_tests/relatedapp/models.py index baa1e7ff33..606b40c52a 100644 --- a/tests/gis_tests/relatedapp/models.py +++ b/tests/gis_tests/relatedapp/models.py @@ -24,7 +24,7 @@ class Location(SimpleModel): class City(SimpleModel): name = models.CharField(max_length=50) state = models.CharField(max_length=2) - location = models.ForeignKey(Location) + location = models.ForeignKey(Location, models.CASCADE) def __str__(self): return self.name @@ -38,13 +38,13 @@ class AugmentedLocation(Location): class DirectoryEntry(SimpleModel): listing_text = models.CharField(max_length=50) - location = models.ForeignKey(AugmentedLocation) + location = models.ForeignKey(AugmentedLocation, models.CASCADE) @python_2_unicode_compatible class Parcel(SimpleModel): name = models.CharField(max_length=30) - city = models.ForeignKey(City) + city = models.ForeignKey(City, models.CASCADE) center1 = models.PointField() # Throwing a curveball w/`db_column` here. center2 = models.PointField(srid=2276, db_column='mycenter') @@ -63,12 +63,12 @@ class Author(SimpleModel): class Article(SimpleModel): title = models.CharField(max_length=100) - author = models.ForeignKey(Author, unique=True) + author = models.ForeignKey(Author, models.CASCADE, unique=True) class Book(SimpleModel): title = models.CharField(max_length=100) - author = models.ForeignKey(Author, related_name='books', null=True) + author = models.ForeignKey(Author, models.SET_NULL, related_name='books', null=True) class Event(SimpleModel): diff --git a/tests/indexes/models.py b/tests/indexes/models.py index 3e9cbf630b..b348f0365c 100644 --- a/tests/indexes/models.py +++ b/tests/indexes/models.py @@ -8,17 +8,17 @@ class CurrentTranslation(models.ForeignObject): # Avoid validation requires_unique_target = False - def __init__(self, to, from_fields, to_fields, **kwargs): + def __init__(self, to, on_delete, from_fields, to_fields, **kwargs): # Disable reverse relation kwargs['related_name'] = '+' # Set unique to enable model cache. kwargs['unique'] = True - super(CurrentTranslation, self).__init__(to, from_fields, to_fields, **kwargs) + super(CurrentTranslation, self).__init__(to, on_delete, from_fields, to_fields, **kwargs) class ArticleTranslation(models.Model): - article = models.ForeignKey('indexes.Article') + article = models.ForeignKey('indexes.Article', models.CASCADE) language = models.CharField(max_length=10, unique=True) content = models.TextField() @@ -28,7 +28,7 @@ class Article(models.Model): pub_date = models.DateTimeField() # Add virtual relation to the ArticleTranslation model. - translation = CurrentTranslation(ArticleTranslation, ['id'], ['article']) + translation = CurrentTranslation(ArticleTranslation, models.CASCADE, ['id'], ['article']) class Meta: index_together = [ diff --git a/tests/inline_formsets/models.py b/tests/inline_formsets/models.py index f29362e321..d94069d5db 100644 --- a/tests/inline_formsets/models.py +++ b/tests/inline_formsets/models.py @@ -12,9 +12,9 @@ class Parent(models.Model): class Child(models.Model): - mother = models.ForeignKey(Parent, related_name='mothers_children') - father = models.ForeignKey(Parent, related_name='fathers_children') - school = models.ForeignKey(School) + mother = models.ForeignKey(Parent, models.CASCADE, related_name='mothers_children') + father = models.ForeignKey(Parent, models.CASCADE, related_name='fathers_children') + school = models.ForeignKey(School, models.CASCADE) name = models.CharField(max_length=100) @@ -28,7 +28,7 @@ class Poet(models.Model): @python_2_unicode_compatible class Poem(models.Model): - poet = models.ForeignKey(Poet) + poet = models.ForeignKey(Poet, models.CASCADE) name = models.CharField(max_length=100) def __str__(self): diff --git a/tests/inspectdb/models.py b/tests/inspectdb/models.py index 5c968c6f9f..f7d365b868 100644 --- a/tests/inspectdb/models.py +++ b/tests/inspectdb/models.py @@ -6,20 +6,20 @@ from django.db import models class People(models.Model): name = models.CharField(max_length=255) - parent = models.ForeignKey('self') + parent = models.ForeignKey('self', models.CASCADE) class Message(models.Model): - from_field = models.ForeignKey(People, db_column='from_id') + from_field = models.ForeignKey(People, models.CASCADE, db_column='from_id') class PeopleData(models.Model): - people_pk = models.ForeignKey(People, primary_key=True) + people_pk = models.ForeignKey(People, models.CASCADE, primary_key=True) ssn = models.CharField(max_length=11) class PeopleMoreData(models.Model): - people_unique = models.ForeignKey(People, unique=True) + people_unique = models.ForeignKey(People, models.CASCADE, unique=True) license = models.CharField(max_length=255) diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py index 70538b1bdf..9bfe609394 100644 --- a/tests/inspectdb/tests.py +++ b/tests/inspectdb/tests.py @@ -144,15 +144,25 @@ class InspectDBTestCase(TestCase): output = out.getvalue() error_message = "inspectdb generated an attribute name which is a python keyword" # Recursive foreign keys should be set to 'self' - self.assertIn("parent = models.ForeignKey('self')", output) - self.assertNotIn("from = models.ForeignKey(InspectdbPeople)", output, msg=error_message) + self.assertIn("parent = models.ForeignKey('self', models.DO_NOTHING)", output) + self.assertNotIn( + "from = models.ForeignKey(InspectdbPeople, models.DO_NOTHING)", + output, + msg=error_message, + ) # As InspectdbPeople model is defined after InspectdbMessage, it should be quoted - self.assertIn("from_field = models.ForeignKey('InspectdbPeople', db_column='from_id')", - output) - self.assertIn("people_pk = models.ForeignKey(InspectdbPeople, primary_key=True)", - output) - self.assertIn("people_unique = models.ForeignKey(InspectdbPeople, unique=True)", - output) + self.assertIn( + "from_field = models.ForeignKey('InspectdbPeople', models.DO_NOTHING, db_column='from_id')", + output, + ) + self.assertIn( + "people_pk = models.ForeignKey(InspectdbPeople, models.DO_NOTHING, primary_key=True)", + output, + ) + self.assertIn( + "people_unique = models.ForeignKey(InspectdbPeople, models.DO_NOTHING, unique=True)", + output, + ) def test_digits_column_name_introspection(self): """Introspection of column names consist/start with digits (#16536/#17676)""" diff --git a/tests/introspection/models.py b/tests/introspection/models.py index 3929509934..9ad52b8f8d 100644 --- a/tests/introspection/models.py +++ b/tests/introspection/models.py @@ -25,8 +25,8 @@ class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateField() body = models.TextField(default='') - reporter = models.ForeignKey(Reporter) - response_to = models.ForeignKey('self', null=True) + reporter = models.ForeignKey(Reporter, models.CASCADE) + response_to = models.ForeignKey('self', models.SET_NULL, null=True) def __str__(self): return self.headline diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py index fe27814f83..a27357a1a6 100644 --- a/tests/invalid_models_tests/test_models.py +++ b/tests/invalid_models_tests/test_models.py @@ -305,22 +305,28 @@ class FieldNamesTests(IsolatedModelsTestCase): related_name="rn3", through='m2mcomplex' ) - fk = models.ForeignKey(VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, related_name="rn4") + fk = models.ForeignKey( + VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, + models.CASCADE, + related_name="rn4", + ) # Models used for setting `through` in M2M field. class m2msimple(models.Model): - id2 = models.ForeignKey(ModelWithLongField) + id2 = models.ForeignKey(ModelWithLongField, models.CASCADE) class m2mcomplex(models.Model): - id2 = models.ForeignKey(ModelWithLongField) + id2 = models.ForeignKey(ModelWithLongField, models.CASCADE) long_field_name = 'a' * (self.max_column_name_length + 1) models.ForeignKey( - VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz + VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, + models.CASCADE, ).contribute_to_class(m2msimple, long_field_name) models.ForeignKey( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, + models.CASCADE, db_column=long_field_name ).contribute_to_class(m2mcomplex, long_field_name) @@ -473,7 +479,7 @@ class ShadowingFieldsTests(IsolatedModelsTestCase): class Child(Parent): # This field clashes with parent "f_id" field. - f = models.ForeignKey(Target) + f = models.ForeignKey(Target, models.CASCADE) errors = Child.check() expected = [ @@ -517,7 +523,7 @@ class ShadowingFieldsTests(IsolatedModelsTestCase): pass class Model(models.Model): - fk = models.ForeignKey(Target) + fk = models.ForeignKey(Target, models.CASCADE) fk_id = models.IntegerField() errors = Model.check() @@ -584,7 +590,7 @@ class OtherModelTests(IsolatedModelsTestCase): pass class Answer(models.Model): - question = models.ForeignKey(Question) + question = models.ForeignKey(Question, models.CASCADE) class Meta: order_with_respect_to = 'question' @@ -596,7 +602,7 @@ class OtherModelTests(IsolatedModelsTestCase): pass class Answer(models.Model): - question = models.ForeignKey(Question) + question = models.ForeignKey(Question, models.CASCADE) order = models.IntegerField() class Meta: @@ -678,7 +684,7 @@ class OtherModelTests(IsolatedModelsTestCase): pass class Child(models.Model): - parent = models.ForeignKey(Parent) + parent = models.ForeignKey(Parent, models.CASCADE) class Meta: ordering = ("parent_id",) @@ -731,8 +737,8 @@ class OtherModelTests(IsolatedModelsTestCase): related_name="secondary") class Membership(models.Model): - person = models.ForeignKey(Person) - group = models.ForeignKey(Group) + person = models.ForeignKey(Person, models.CASCADE) + group = models.ForeignKey(Group, models.CASCADE) errors = Group.check() expected = [ diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py index 5d174d0c9b..7e6d7612fd 100644 --- a/tests/invalid_models_tests/test_relative_fields.py +++ b/tests/invalid_models_tests/test_relative_fields.py @@ -1,11 +1,16 @@ # -*- encoding: utf-8 -*- from __future__ import unicode_literals +import warnings + from django.core.checks import Error, Warning as DjangoWarning from django.db import models +from django.test import ignore_warnings from django.test.testcases import skipIfDBFeature from django.test.utils import override_settings from django.utils import six +from django.utils.deprecation import RemovedInDjango20Warning +from django.utils.version import get_docs_version from .base import IsolatedModelsTestCase @@ -18,18 +23,100 @@ class RelativeFieldTests(IsolatedModelsTestCase): model = models.IntegerField() class Model(models.Model): - field = models.ForeignKey(Target, related_name='+') + field = models.ForeignKey(Target, models.CASCADE, related_name='+') field = Model._meta.get_field('field') errors = field.check() self.assertEqual(errors, []) + @ignore_warnings(category=RemovedInDjango20Warning) + def test_valid_foreign_key_without_on_delete(self): + class Target(models.Model): + model = models.IntegerField() + + class Model(models.Model): + field = models.ForeignKey(Target, related_name='+') + + def test_foreign_key_without_on_delete_warning(self): + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') # prevent warnings from appearing as errors + + class Target(models.Model): + model = models.IntegerField() + + class Model(models.Model): + field = models.ForeignKey(Target, related_name='+') + + self.assertEqual(len(warns), 1) + self.assertEqual( + str(warns[0].message), + 'on_delete will be a required arg for ForeignKey in Django ' + '2.0. Set it to models.CASCADE if you want to maintain the ' + 'current default behavior. See ' + 'https://docs.djangoproject.com/en/%s/ref/models/fields/' + '#django.db.models.ForeignKey.on_delete' % get_docs_version(), + ) + + def test_foreign_key_to_field_as_arg(self): + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') # prevent warnings from appearing as errors + + class Target(models.Model): + model = models.IntegerField() + + class Model(models.Model): + field = models.ForeignKey(Target, 'id') + + self.assertEqual(len(warns), 1) + self.assertEqual( + str(warns[0].message), + "The signature for ForeignKey will change in Django 2.0. " + "Pass to_field='id' as a kwarg instead of as an arg." + ) + + def test_one_to_one_field_without_on_delete_warning(self): + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') # prevent warnings from appearing as errors + + class Target(models.Model): + model = models.IntegerField() + + class Model(models.Model): + field = models.OneToOneField(Target, related_name='+') + + self.assertEqual(len(warns), 1) + self.assertEqual( + str(warns[0].message), + 'on_delete will be a required arg for OneToOneField in Django ' + '2.0. Set it to models.CASCADE if you want to maintain the ' + 'current default behavior. See ' + 'https://docs.djangoproject.com/en/%s/ref/models/fields/' + '#django.db.models.ForeignKey.on_delete' % get_docs_version(), + ) + + def test_one_to_one_field_to_field_as_arg(self): + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') # prevent warnings from appearing as errors + + class Target(models.Model): + model = models.IntegerField() + + class Model(models.Model): + field = models.OneToOneField(Target, 'id') + + self.assertEqual(len(warns), 1) + self.assertEqual( + str(warns[0].message), + "The signature for OneToOneField will change in Django 2.0. " + "Pass to_field='id' as a kwarg instead of as an arg." + ) + def test_foreign_key_to_missing_model(self): # Model names are resolved when a model is being created, so we cannot # test relative fields in isolation and we need to attach them to a # model. class Model(models.Model): - foreign_key = models.ForeignKey('Rel1') + foreign_key = models.ForeignKey('Rel1', models.CASCADE) field = Model._meta.get_field('foreign_key') errors = field.check() @@ -101,9 +188,9 @@ class RelativeFieldTests(IsolatedModelsTestCase): class AmbiguousRelationship(models.Model): # Too much foreign keys to Person. - first_person = models.ForeignKey(Person, related_name="first") - second_person = models.ForeignKey(Person, related_name="second") - second_model = models.ForeignKey(Group) + first_person = models.ForeignKey(Person, models.CASCADE, related_name="first") + second_person = models.ForeignKey(Person, models.CASCADE, related_name="second") + second_model = models.ForeignKey(Group, models.CASCADE) field = Group._meta.get_field('field') errors = field.check(from_model=Group) @@ -135,8 +222,8 @@ class RelativeFieldTests(IsolatedModelsTestCase): through="InvalidRelationship") class InvalidRelationship(models.Model): - person = models.ForeignKey(Person) - wrong_foreign_key = models.ForeignKey(WrongModel) + person = models.ForeignKey(Person, models.CASCADE) + wrong_foreign_key = models.ForeignKey(WrongModel, models.CASCADE) # The last foreign key should point to Group model. field = Group._meta.get_field('members') @@ -162,7 +249,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): through="InvalidRelationship") class InvalidRelationship(models.Model): - group = models.ForeignKey(Group) + group = models.ForeignKey(Group, models.CASCADE) # No foreign key to Person field = Group._meta.get_field('members') @@ -206,8 +293,8 @@ class RelativeFieldTests(IsolatedModelsTestCase): friends = models.ManyToManyField('self', through="Relationship") class Relationship(models.Model): - first = models.ForeignKey(Person, related_name="rel_from_set") - second = models.ForeignKey(Person, related_name="rel_to_set") + first = models.ForeignKey(Person, models.CASCADE, related_name="rel_from_set") + second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set") field = Person._meta.get_field('friends') errors = field.check(from_model=Person) @@ -227,9 +314,9 @@ class RelativeFieldTests(IsolatedModelsTestCase): through="InvalidRelationship", symmetrical=False) class InvalidRelationship(models.Model): - first = models.ForeignKey(Person, related_name="rel_from_set_2") - second = models.ForeignKey(Person, related_name="rel_to_set_2") - third = models.ForeignKey(Person, related_name="too_many_by_far") + first = models.ForeignKey(Person, models.CASCADE, related_name="rel_from_set_2") + second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set_2") + third = models.ForeignKey(Person, models.CASCADE, related_name="too_many_by_far") field = Person._meta.get_field('friends') errors = field.check(from_model=Person) @@ -254,8 +341,8 @@ class RelativeFieldTests(IsolatedModelsTestCase): through="Relationship", symmetrical=True) class Relationship(models.Model): - first = models.ForeignKey(Person, related_name="rel_from_set") - second = models.ForeignKey(Person, related_name="rel_to_set") + first = models.ForeignKey(Person, models.CASCADE, related_name="rel_from_set") + second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set") field = Person._meta.get_field('friends') errors = field.check(from_model=Person) @@ -279,9 +366,9 @@ class RelativeFieldTests(IsolatedModelsTestCase): through_fields=('first', 'second')) class Relationship(models.Model): - first = models.ForeignKey(Person, related_name="rel_from_set") - second = models.ForeignKey(Person, related_name="rel_to_set") - referee = models.ForeignKey(Person, related_name="referred") + first = models.ForeignKey(Person, models.CASCADE, related_name="rel_from_set") + second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set") + referee = models.ForeignKey(Person, models.CASCADE, related_name="referred") field = Person._meta.get_field('friends') errors = field.check(from_model=Person) @@ -297,7 +384,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): def test_foreign_key_to_abstract_model(self): class Model(models.Model): - foreign_key = models.ForeignKey('AbstractModel') + foreign_key = models.ForeignKey('AbstractModel', models.CASCADE) class AbstractModel(models.Model): class Meta: @@ -361,7 +448,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): bad = models.IntegerField() # No unique=True class Model(models.Model): - foreign_key = models.ForeignKey('Target', to_field='bad') + foreign_key = models.ForeignKey('Target', models.CASCADE, to_field='bad') field = Model._meta.get_field('foreign_key') errors = field.check() @@ -380,7 +467,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): bad = models.IntegerField() class Model(models.Model): - field = models.ForeignKey(Target, to_field='bad') + field = models.ForeignKey(Target, models.CASCADE, to_field='bad') field = Model._meta.get_field('field') errors = field.check() @@ -405,6 +492,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): person_city_id = models.IntegerField() person = models.ForeignObject(Person, + on_delete=models.CASCADE, from_fields=['person_country_id', 'person_city_id'], to_fields=['country_id', 'city_id']) @@ -426,8 +514,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): pass class Model(models.Model): - foreign_key = models.ForeignKey('Person', - on_delete=models.SET_NULL) + foreign_key = models.ForeignKey('Person', models.SET_NULL) field = Model._meta.get_field('foreign_key') errors = field.check() @@ -446,8 +533,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): pass class Model(models.Model): - foreign_key = models.ForeignKey('Person', - on_delete=models.SET_DEFAULT) + foreign_key = models.ForeignKey('Person', models.SET_DEFAULT) field = Model._meta.get_field('foreign_key') errors = field.check() @@ -487,8 +573,10 @@ class RelativeFieldTests(IsolatedModelsTestCase): class Model(models.Model): explicit_fk = models.ForeignKey(SwappableModel, + models.CASCADE, related_name='explicit_fk') implicit_fk = models.ForeignKey('invalid_models_tests.SwappableModel', + models.CASCADE, related_name='implicit_fk') explicit_m2m = models.ManyToManyField(SwappableModel, related_name='explicit_m2m') @@ -519,8 +607,10 @@ class RelativeFieldTests(IsolatedModelsTestCase): class Model(models.Model): explicit_fk = models.ForeignKey(SwappedModel, + models.CASCADE, related_name='explicit_fk') implicit_fk = models.ForeignKey('invalid_models_tests.SwappedModel', + models.CASCADE, related_name='implicit_fk') explicit_m2m = models.ManyToManyField(SwappedModel, related_name='explicit_m2m') @@ -572,7 +662,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): for invalid_related_name in invalid_related_names: Child = type(str('Child_%s') % str(invalid_related_name), (models.Model,), { - 'parent': models.ForeignKey('Parent', related_name=invalid_related_name), + 'parent': models.ForeignKey('Parent', models.CASCADE, related_name=invalid_related_name), '__module__': Parent.__module__, }) @@ -613,7 +703,7 @@ class RelativeFieldTests(IsolatedModelsTestCase): for related_name in related_names: Child = type(str('Child_%s') % str(related_name), (models.Model,), { - 'parent': models.ForeignKey('Parent', related_name=related_name), + 'parent': models.ForeignKey('Parent', models.CASCADE, related_name=related_name), '__module__': Parent.__module__, }) @@ -626,17 +716,17 @@ class AccessorClashTests(IsolatedModelsTestCase): def test_fk_to_integer(self): self._test_accessor_clash( target=models.IntegerField(), - relative=models.ForeignKey('Target')) + relative=models.ForeignKey('Target', models.CASCADE)) def test_fk_to_fk(self): self._test_accessor_clash( - target=models.ForeignKey('Another'), - relative=models.ForeignKey('Target')) + target=models.ForeignKey('Another', models.CASCADE), + relative=models.ForeignKey('Target', models.CASCADE)) def test_fk_to_m2m(self): self._test_accessor_clash( target=models.ManyToManyField('Another'), - relative=models.ForeignKey('Target')) + relative=models.ForeignKey('Target', models.CASCADE)) def test_m2m_to_integer(self): self._test_accessor_clash( @@ -645,7 +735,7 @@ class AccessorClashTests(IsolatedModelsTestCase): def test_m2m_to_fk(self): self._test_accessor_clash( - target=models.ForeignKey('Another'), + target=models.ForeignKey('Another', models.CASCADE), relative=models.ManyToManyField('Target')) def test_m2m_to_m2m(self): @@ -681,7 +771,7 @@ class AccessorClashTests(IsolatedModelsTestCase): pass class Model(models.Model): - foreign = models.ForeignKey(Target) + foreign = models.ForeignKey(Target, models.CASCADE) m2m = models.ManyToManyField(Target) errors = Model.check() @@ -738,17 +828,17 @@ class ReverseQueryNameClashTests(IsolatedModelsTestCase): def test_fk_to_integer(self): self._test_reverse_query_name_clash( target=models.IntegerField(), - relative=models.ForeignKey('Target')) + relative=models.ForeignKey('Target', models.CASCADE)) def test_fk_to_fk(self): self._test_reverse_query_name_clash( - target=models.ForeignKey('Another'), - relative=models.ForeignKey('Target')) + target=models.ForeignKey('Another', models.CASCADE), + relative=models.ForeignKey('Target', models.CASCADE)) def test_fk_to_m2m(self): self._test_reverse_query_name_clash( target=models.ManyToManyField('Another'), - relative=models.ForeignKey('Target')) + relative=models.ForeignKey('Target', models.CASCADE)) def test_m2m_to_integer(self): self._test_reverse_query_name_clash( @@ -757,7 +847,7 @@ class ReverseQueryNameClashTests(IsolatedModelsTestCase): def test_m2m_to_fk(self): self._test_reverse_query_name_clash( - target=models.ForeignKey('Another'), + target=models.ForeignKey('Another', models.CASCADE), relative=models.ManyToManyField('Target')) def test_m2m_to_m2m(self): @@ -794,17 +884,17 @@ class ExplicitRelatedNameClashTests(IsolatedModelsTestCase): def test_fk_to_integer(self): self._test_explicit_related_name_clash( target=models.IntegerField(), - relative=models.ForeignKey('Target', related_name='clash')) + relative=models.ForeignKey('Target', models.CASCADE, related_name='clash')) def test_fk_to_fk(self): self._test_explicit_related_name_clash( - target=models.ForeignKey('Another'), - relative=models.ForeignKey('Target', related_name='clash')) + target=models.ForeignKey('Another', models.CASCADE), + relative=models.ForeignKey('Target', models.CASCADE, related_name='clash')) def test_fk_to_m2m(self): self._test_explicit_related_name_clash( target=models.ManyToManyField('Another'), - relative=models.ForeignKey('Target', related_name='clash')) + relative=models.ForeignKey('Target', models.CASCADE, related_name='clash')) def test_m2m_to_integer(self): self._test_explicit_related_name_clash( @@ -813,7 +903,7 @@ class ExplicitRelatedNameClashTests(IsolatedModelsTestCase): def test_m2m_to_fk(self): self._test_explicit_related_name_clash( - target=models.ForeignKey('Another'), + target=models.ForeignKey('Another', models.CASCADE), relative=models.ManyToManyField('Target', related_name='clash')) def test_m2m_to_m2m(self): @@ -859,18 +949,21 @@ class ExplicitRelatedQueryNameClashTests(IsolatedModelsTestCase): self._test_explicit_related_query_name_clash( target=models.IntegerField(), relative=models.ForeignKey('Target', + models.CASCADE, related_query_name='clash')) def test_fk_to_fk(self): self._test_explicit_related_query_name_clash( - target=models.ForeignKey('Another'), + target=models.ForeignKey('Another', models.CASCADE), relative=models.ForeignKey('Target', + models.CASCADE, related_query_name='clash')) def test_fk_to_m2m(self): self._test_explicit_related_query_name_clash( target=models.ManyToManyField('Another'), relative=models.ForeignKey('Target', + models.CASCADE, related_query_name='clash')) def test_m2m_to_integer(self): @@ -881,7 +974,7 @@ class ExplicitRelatedQueryNameClashTests(IsolatedModelsTestCase): def test_m2m_to_fk(self): self._test_explicit_related_query_name_clash( - target=models.ForeignKey('Another'), + target=models.ForeignKey('Another', models.CASCADE), relative=models.ManyToManyField('Target', related_query_name='clash')) @@ -1013,7 +1106,7 @@ class SelfReferentialFKClashTests(IsolatedModelsTestCase): def test_accessor_clash(self): class Model(models.Model): - model_set = models.ForeignKey("Model") + model_set = models.ForeignKey("Model", models.CASCADE) errors = Model.check() expected = [ @@ -1030,7 +1123,7 @@ class SelfReferentialFKClashTests(IsolatedModelsTestCase): def test_reverse_query_name_clash(self): class Model(models.Model): - model = models.ForeignKey("Model") + model = models.ForeignKey("Model", models.CASCADE) errors = Model.check() expected = [ @@ -1048,7 +1141,7 @@ class SelfReferentialFKClashTests(IsolatedModelsTestCase): def test_clash_under_explicit_related_name(self): class Model(models.Model): clash = models.CharField(max_length=10) - foreign = models.ForeignKey("Model", related_name='clash') + foreign = models.ForeignKey("Model", models.CASCADE, related_name='clash') errors = Model.check() expected = [ @@ -1087,8 +1180,8 @@ class ComplexClashTests(IsolatedModelsTestCase): class Model(models.Model): src_safe = models.CharField(max_length=10) - foreign_1 = models.ForeignKey(Target, related_name='id') - foreign_2 = models.ForeignKey(Target, related_name='src_safe') + foreign_1 = models.ForeignKey(Target, models.CASCADE, related_name='id') + foreign_2 = models.ForeignKey(Target, models.CASCADE, related_name='src_safe') m2m_1 = models.ManyToManyField(Target, related_name='id') m2m_2 = models.ManyToManyField(Target, related_name='src_safe') @@ -1211,9 +1304,9 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase): invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('invitee', 'event')) class Invitation(models.Model): - event = models.ForeignKey(Event) - invitee = models.ForeignKey(Fan) - inviter = models.ForeignKey(Fan, related_name='+') + event = models.ForeignKey(Event, models.CASCADE) + invitee = models.ForeignKey(Fan, models.CASCADE) + inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+') field = Event._meta.get_field('invitees') errors = field.check(from_model=Event) @@ -1243,9 +1336,9 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase): invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('invalid_field_1', 'invalid_field_2')) class Invitation(models.Model): - event = models.ForeignKey(Event) - invitee = models.ForeignKey(Fan) - inviter = models.ForeignKey(Fan, related_name='+') + event = models.ForeignKey(Event, models.CASCADE) + invitee = models.ForeignKey(Fan, models.CASCADE) + inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+') field = Event._meta.get_field('invitees') errors = field.check(from_model=Event) @@ -1275,9 +1368,9 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase): invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=(None, 'invitee')) class Invitation(models.Model): - event = models.ForeignKey(Event) - invitee = models.ForeignKey(Fan) - inviter = models.ForeignKey(Fan, related_name='+') + event = models.ForeignKey(Event, models.CASCADE) + invitee = models.ForeignKey(Fan, models.CASCADE) + inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+') field = Event._meta.get_field('invitees') errors = field.check(from_model=Event) diff --git a/tests/known_related_objects/models.py b/tests/known_related_objects/models.py index 2b5ab6cfe5..69cb26706a 100644 --- a/tests/known_related_objects/models.py +++ b/tests/known_related_objects/models.py @@ -17,10 +17,10 @@ class Organiser(models.Model): class Pool(models.Model): name = models.CharField(max_length=30) - tournament = models.ForeignKey(Tournament) - organiser = models.ForeignKey(Organiser) + tournament = models.ForeignKey(Tournament, models.CASCADE) + organiser = models.ForeignKey(Organiser, models.CASCADE) class PoolStyle(models.Model): name = models.CharField(max_length=30) - pool = models.OneToOneField(Pool) + pool = models.OneToOneField(Pool, models.CASCADE) diff --git a/tests/lookup/models.py b/tests/lookup/models.py index 504bbf9d25..b8e47ec746 100644 --- a/tests/lookup/models.py +++ b/tests/lookup/models.py @@ -30,7 +30,7 @@ class Author(models.Model): class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateTimeField() - author = models.ForeignKey(Author, blank=True, null=True) + author = models.ForeignKey(Author, models.SET_NULL, blank=True, null=True) class Meta: ordering = ('-pub_date', 'headline') @@ -58,7 +58,7 @@ class Season(models.Model): @python_2_unicode_compatible class Game(models.Model): - season = models.ForeignKey(Season, related_name='games') + season = models.ForeignKey(Season, models.CASCADE, related_name='games') home = models.CharField(max_length=100) away = models.CharField(max_length=100) diff --git a/tests/m2m_and_m2o/models.py b/tests/m2m_and_m2o/models.py index 753820fade..60f5c43733 100644 --- a/tests/m2m_and_m2o/models.py +++ b/tests/m2m_and_m2o/models.py @@ -18,7 +18,7 @@ class User(models.Model): class Issue(models.Model): num = models.IntegerField() cc = models.ManyToManyField(User, blank=True, related_name='test_issue_cc') - client = models.ForeignKey(User, related_name='test_issue_client') + client = models.ForeignKey(User, models.CASCADE, related_name='test_issue_client') def __str__(self): return six.text_type(self.num) diff --git a/tests/m2m_intermediary/models.py b/tests/m2m_intermediary/models.py index e853984be5..3e73164e6f 100644 --- a/tests/m2m_intermediary/models.py +++ b/tests/m2m_intermediary/models.py @@ -35,8 +35,8 @@ class Article(models.Model): @python_2_unicode_compatible class Writer(models.Model): - reporter = models.ForeignKey(Reporter) - article = models.ForeignKey(Article) + reporter = models.ForeignKey(Reporter, models.CASCADE) + article = models.ForeignKey(Article, models.CASCADE) position = models.CharField(max_length=100) def __str__(self): diff --git a/tests/m2m_through/models.py b/tests/m2m_through/models.py index c30b21612b..32f93981a7 100644 --- a/tests/m2m_through/models.py +++ b/tests/m2m_through/models.py @@ -32,8 +32,8 @@ class Group(models.Model): @python_2_unicode_compatible class Membership(models.Model): - person = models.ForeignKey(Person) - group = models.ForeignKey(Group) + person = models.ForeignKey(Person, models.CASCADE) + group = models.ForeignKey(Group, models.CASCADE) date_joined = models.DateTimeField(default=datetime.now) invite_reason = models.CharField(max_length=64, null=True) @@ -46,9 +46,14 @@ class Membership(models.Model): @python_2_unicode_compatible class CustomMembership(models.Model): - person = models.ForeignKey(Person, db_column="custom_person_column", related_name="custom_person_related_name") - group = models.ForeignKey(Group) - weird_fk = models.ForeignKey(Membership, null=True) + person = models.ForeignKey( + Person, + models.CASCADE, + db_column="custom_person_column", + related_name="custom_person_related_name", + ) + group = models.ForeignKey(Group, models.CASCADE) + weird_fk = models.ForeignKey(Membership, models.SET_NULL, null=True) date_joined = models.DateTimeField(default=datetime.now) def __str__(self): @@ -59,8 +64,8 @@ class CustomMembership(models.Model): class TestNoDefaultsOrNulls(models.Model): - person = models.ForeignKey(Person) - group = models.ForeignKey(Group) + person = models.ForeignKey(Person, models.CASCADE) + group = models.ForeignKey(Group, models.CASCADE) nodefaultnonull = models.CharField(max_length=5) @@ -74,8 +79,8 @@ class PersonSelfRefM2M(models.Model): class Friendship(models.Model): - first = models.ForeignKey(PersonSelfRefM2M, related_name="rel_from_set") - second = models.ForeignKey(PersonSelfRefM2M, related_name="rel_to_set") + first = models.ForeignKey(PersonSelfRefM2M, models.CASCADE, related_name="rel_from_set") + second = models.ForeignKey(PersonSelfRefM2M, models.CASCADE, related_name="rel_to_set") date_friended = models.DateTimeField() @@ -90,10 +95,10 @@ class Event(models.Model): class Invitation(models.Model): - event = models.ForeignKey(Event, related_name='invitations') + event = models.ForeignKey(Event, models.CASCADE, related_name='invitations') # field order is deliberately inverted. the target field is "invitee". - inviter = models.ForeignKey(Person, related_name='invitations_sent') - invitee = models.ForeignKey(Person, related_name='invitations') + inviter = models.ForeignKey(Person, models.CASCADE, related_name='invitations_sent') + invitee = models.ForeignKey(Person, models.CASCADE, related_name='invitations') @python_2_unicode_compatible @@ -110,9 +115,9 @@ class Employee(models.Model): class Relationship(models.Model): # field order is deliberately inverted. - another = models.ForeignKey(Employee, related_name="rel_another_set", null=True) - target = models.ForeignKey(Employee, related_name="rel_target_set") - source = models.ForeignKey(Employee, related_name="rel_source_set") + another = models.ForeignKey(Employee, models.SET_NULL, related_name="rel_another_set", null=True) + target = models.ForeignKey(Employee, models.CASCADE, related_name="rel_target_set") + source = models.ForeignKey(Employee, models.CASCADE, related_name="rel_source_set") class Ingredient(models.Model): @@ -133,5 +138,5 @@ class Recipe(models.Model): class RecipeIngredient(models.Model): - ingredient = models.ForeignKey(Ingredient, to_field='iname') - recipe = models.ForeignKey(Recipe, to_field='rname') + ingredient = models.ForeignKey(Ingredient, models.CASCADE, to_field='iname') + recipe = models.ForeignKey(Recipe, models.CASCADE, to_field='rname') diff --git a/tests/m2m_through_regress/models.py b/tests/m2m_through_regress/models.py index c49e5b02eb..10dcddfc58 100644 --- a/tests/m2m_through_regress/models.py +++ b/tests/m2m_through_regress/models.py @@ -8,8 +8,8 @@ from django.utils.encoding import python_2_unicode_compatible # Forward declared intermediate model @python_2_unicode_compatible class Membership(models.Model): - person = models.ForeignKey('Person') - group = models.ForeignKey('Group') + person = models.ForeignKey('Person', models.CASCADE) + group = models.ForeignKey('Group', models.CASCADE) price = models.IntegerField(default=100) def __str__(self): @@ -20,8 +20,8 @@ class Membership(models.Model): @python_2_unicode_compatible class UserMembership(models.Model): id = models.AutoField(db_column='usermembership_id', primary_key=True) - user = models.ForeignKey(User) - group = models.ForeignKey('Group') + user = models.ForeignKey(User, models.CASCADE) + group = models.ForeignKey('Group', models.CASCADE) price = models.IntegerField(default=100) def __str__(self): @@ -53,8 +53,8 @@ class A(models.Model): class ThroughBase(models.Model): - a = models.ForeignKey(A) - b = models.ForeignKey('B') + a = models.ForeignKey(A, models.CASCADE) + b = models.ForeignKey('B', models.CASCADE) class Through(ThroughBase): @@ -89,8 +89,8 @@ class Driver(models.Model): @python_2_unicode_compatible class CarDriver(models.Model): - car = models.ForeignKey('Car', to_field='make') - driver = models.ForeignKey('Driver', to_field='name') + car = models.ForeignKey('Car', models.CASCADE, to_field='make') + driver = models.ForeignKey('Driver', models.CASCADE, to_field='name') def __str__(self): return "pk=%s car=%s driver=%s" % (str(self.pk), self.car, self.driver) diff --git a/tests/m2o_recursive/models.py b/tests/m2o_recursive/models.py index ac6ca8451d..d62c514a25 100644 --- a/tests/m2o_recursive/models.py +++ b/tests/m2o_recursive/models.py @@ -2,7 +2,7 @@ Relating an object to itself, many-to-one To define a many-to-one relationship between a model and itself, use -``ForeignKey('self')``. +``ForeignKey('self', ...)``. In this example, a ``Category`` is related to itself. That is, each ``Category`` has a parent ``Category``. @@ -17,7 +17,7 @@ from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class Category(models.Model): name = models.CharField(max_length=20) - parent = models.ForeignKey('self', blank=True, null=True, related_name='child_set') + parent = models.ForeignKey('self', models.SET_NULL, blank=True, null=True, related_name='child_set') def __str__(self): return self.name @@ -26,8 +26,8 @@ class Category(models.Model): @python_2_unicode_compatible class Person(models.Model): full_name = models.CharField(max_length=20) - mother = models.ForeignKey('self', null=True, related_name='mothers_child_set') - father = models.ForeignKey('self', null=True, related_name='fathers_child_set') + mother = models.ForeignKey('self', models.SET_NULL, null=True, related_name='mothers_child_set') + father = models.ForeignKey('self', models.SET_NULL, null=True, related_name='fathers_child_set') def __str__(self): return self.full_name diff --git a/tests/managers_regress/models.py b/tests/managers_regress/models.py index 16849ed913..bc2fa91c6a 100644 --- a/tests/managers_regress/models.py +++ b/tests/managers_regress/models.py @@ -137,11 +137,11 @@ class RelatedModel(models.Model): @python_2_unicode_compatible class RelationModel(models.Model): - fk = models.ForeignKey(RelatedModel, related_name='test_fk') + fk = models.ForeignKey(RelatedModel, models.CASCADE, related_name='test_fk') m2m = models.ManyToManyField(RelatedModel, related_name='test_m2m') - gfk_ctype = models.ForeignKey(ContentType, null=True) + gfk_ctype = models.ForeignKey(ContentType, models.SET_NULL, null=True) gfk_id = models.IntegerField(null=True) gfk = GenericForeignKey(ct_field='gfk_ctype', fk_field='gfk_id') diff --git a/tests/many_to_one/models.py b/tests/many_to_one/models.py index 6451d9ff2f..57fc7a617b 100644 --- a/tests/many_to_one/models.py +++ b/tests/many_to_one/models.py @@ -23,7 +23,7 @@ class Reporter(models.Model): class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateField() - reporter = models.ForeignKey(Reporter) + reporter = models.ForeignKey(Reporter, models.CASCADE) def __str__(self): return self.headline @@ -40,27 +40,27 @@ class First(models.Model): class Second(models.Model): - first = models.ForeignKey(First, related_name='the_first') + first = models.ForeignKey(First, models.CASCADE, related_name='the_first') # Protect against repetition of #1839, #2415 and #2536. class Third(models.Model): name = models.CharField(max_length=20) - third = models.ForeignKey('self', null=True, related_name='child_set') + third = models.ForeignKey('self', models.SET_NULL, null=True, related_name='child_set') class Parent(models.Model): name = models.CharField(max_length=20, unique=True) - bestchild = models.ForeignKey('Child', null=True, related_name='favored_by') + bestchild = models.ForeignKey('Child', models.SET_NULL, null=True, related_name='favored_by') class Child(models.Model): name = models.CharField(max_length=20) - parent = models.ForeignKey(Parent) + parent = models.ForeignKey(Parent, models.CASCADE) class ToFieldChild(models.Model): - parent = models.ForeignKey(Parent, to_field='name') + parent = models.ForeignKey(Parent, models.CASCADE, to_field='name') # Multiple paths to the same model (#7110, #7125) @@ -73,13 +73,13 @@ class Category(models.Model): class Record(models.Model): - category = models.ForeignKey(Category) + category = models.ForeignKey(Category, models.CASCADE) @python_2_unicode_compatible class Relation(models.Model): - left = models.ForeignKey(Record, related_name='left_set') - right = models.ForeignKey(Record, related_name='right_set') + left = models.ForeignKey(Record, models.CASCADE, related_name='left_set') + right = models.ForeignKey(Record, models.CASCADE, related_name='right_set') def __str__(self): return "%s - %s" % (self.left.category.name, self.right.category.name) @@ -97,4 +97,4 @@ class School(models.Model): class Student(models.Model): - school = models.ForeignKey(School) + school = models.ForeignKey(School, models.CASCADE) diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py index d828abe8c2..7b2a640b2b 100644 --- a/tests/many_to_one/tests.py +++ b/tests/many_to_one/tests.py @@ -173,7 +173,7 @@ class ManyToOneTests(TestCase): name = models.CharField(max_length=50) class BandMember(models.Model): - band = UnsavedForeignKey(Band) + band = UnsavedForeignKey(Band, models.CASCADE) first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @@ -609,7 +609,7 @@ class ManyToOneTests(TestCase): def test_fk_instantiation_outside_model(self): # Regression for #12190 -- Should be able to instantiate a FK outside # of a model, and interrogate its related field. - cat = models.ForeignKey(Category) + cat = models.ForeignKey(Category, models.CASCADE) self.assertEqual('id', cat.remote_field.get_related_field().name) def test_relation_unsaved(self): diff --git a/tests/many_to_one_null/models.py b/tests/many_to_one_null/models.py index 3cf8a512ab..2a67623dc3 100644 --- a/tests/many_to_one_null/models.py +++ b/tests/many_to_one_null/models.py @@ -20,7 +20,7 @@ class Reporter(models.Model): @python_2_unicode_compatible class Article(models.Model): headline = models.CharField(max_length=100) - reporter = models.ForeignKey(Reporter, null=True) + reporter = models.ForeignKey(Reporter, models.SET_NULL, null=True) class Meta: ordering = ('headline',) @@ -34,4 +34,4 @@ class Car(models.Model): class Driver(models.Model): - car = models.ForeignKey(Car, to_field='make', null=True, related_name='drivers') + car = models.ForeignKey(Car, models.SET_NULL, to_field='make', null=True, related_name='drivers') diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py index c929e4f075..7769e4b32a 100644 --- a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=50)), - ('author', models.ForeignKey('author_app.Author')), + ('author', models.ForeignKey('author_app.Author', models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py index 34f3c6c062..8dd1bf977b 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py @@ -17,8 +17,8 @@ class Migration(migrations.Migration): name='A3', fields=[ ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), - ('b2', models.ForeignKey(to='lookuperror_b.B2')), - ('c2', models.ForeignKey(to='lookuperror_c.C2')), + ('b2', models.ForeignKey('lookuperror_b.B2', models.CASCADE)), + ('c2', models.ForeignKey('lookuperror_c.C2', models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/models.py b/tests/migrations/migrations_test_apps/lookuperror_a/models.py index 65dfb6bd85..9428f952eb 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/models.py @@ -10,8 +10,8 @@ class A2(models.Model): class A3(models.Model): - b2 = models.ForeignKey('lookuperror_b.B2') - c2 = models.ForeignKey('lookuperror_c.C2') + b2 = models.ForeignKey('lookuperror_b.B2', models.CASCADE) + c2 = models.ForeignKey('lookuperror_c.C2', models.CASCADE) class A4(models.Model): diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py index 70ba124a0d..7e91505cd2 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name='B2', fields=[ ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('a1', models.ForeignKey(to='lookuperror_a.A1')), + ('a1', models.ForeignKey('lookuperror_a.A1', models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/models.py b/tests/migrations/migrations_test_apps/lookuperror_b/models.py index f2c21aa1d4..ed78c48e68 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/models.py @@ -6,7 +6,7 @@ class B1(models.Model): class B2(models.Model): - a1 = models.ForeignKey('lookuperror_a.A1') + a1 = models.ForeignKey('lookuperror_a.A1', models.CASCADE) class B3(models.Model): diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py index 12942c23b1..ca557688aa 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name='C2', fields=[ ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), - ('a1', models.ForeignKey(to='lookuperror_a.A1')), + ('a1', models.ForeignKey('lookuperror_a.A1', models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/models.py b/tests/migrations/migrations_test_apps/lookuperror_c/models.py index d52a1e7543..5dc28ae5ba 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/models.py @@ -6,7 +6,7 @@ class C1(models.Model): class C2(models.Model): - a1 = models.ForeignKey('lookuperror_a.A1') + a1 = models.ForeignKey('lookuperror_a.A1', models.CASCADE) class C3(models.Model): diff --git a/tests/migrations/migrations_test_apps/unmigrated_app/models.py b/tests/migrations/migrations_test_apps/unmigrated_app/models.py index a06b4ac159..793e03829f 100644 --- a/tests/migrations/migrations_test_apps/unmigrated_app/models.py +++ b/tests/migrations/migrations_test_apps/unmigrated_app/models.py @@ -6,5 +6,5 @@ from django.db import models class SillyModel(models.Model): silly_field = models.BooleanField(default=False) - silly_tribble = models.ForeignKey("migrations.Tribble") + silly_tribble = models.ForeignKey("migrations.Tribble", models.CASCADE) is_trouble = models.BooleanField(default=True) diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py index 7afce3d20b..1c5ad9d2c2 100644 --- a/tests/migrations/test_autodetector.py +++ b/tests/migrations/test_autodetector.py @@ -183,17 +183,17 @@ class AutodetectorTests(TestCase): author_with_book = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book")), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), ]) author_with_book_order_wrt = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book")), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), ], options={"order_with_respect_to": "book"}) author_renamed_with_book = ModelState("testapp", "Writer", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book")), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), ]) author_with_publisher_string = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), @@ -203,17 +203,17 @@ class AutodetectorTests(TestCase): author_with_publisher = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("publisher", models.ForeignKey("testapp.Publisher")), + ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), ]) author_with_user = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("user", models.ForeignKey("auth.User")), + ("user", models.ForeignKey("auth.User", models.CASCADE)), ]) author_with_custom_user = ModelState("testapp", "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), - ("user", models.ForeignKey("thirdapp.CustomUser")), + ("user", models.ForeignKey("thirdapp.CustomUser", models.CASCADE)), ]) author_proxy = ModelState("testapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",)) author_proxy_options = ModelState("testapp", "AuthorProxy", [], { @@ -265,8 +265,8 @@ class AutodetectorTests(TestCase): ], {"db_table": "author_three"}) contract = ModelState("testapp", "Contract", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), - ("publisher", models.ForeignKey("testapp.Publisher")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), ]) publisher = ModelState("testapp", "Publisher", [ ("id", models.AutoField(primary_key=True)), @@ -274,17 +274,17 @@ class AutodetectorTests(TestCase): ]) publisher_with_author = ModelState("testapp", "Publisher", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("name", models.CharField(max_length=100)), ]) publisher_with_aardvark_author = ModelState("testapp", "Publisher", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Aardvark")), + ("author", models.ForeignKey("testapp.Aardvark", models.CASCADE)), ("name", models.CharField(max_length=100)), ]) publisher_with_book = ModelState("testapp", "Publisher", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("otherapp.Book")), + ("author", models.ForeignKey("otherapp.Book", models.CASCADE)), ("name", models.CharField(max_length=100)), ]) other_pony = ModelState("otherapp", "Pony", [ @@ -301,17 +301,17 @@ class AutodetectorTests(TestCase): third_thing = ModelState("thirdapp", "Thing", [("id", models.AutoField(primary_key=True))]) book = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("title", models.CharField(max_length=200)), ]) book_proxy_fk = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("thirdapp.AuthorProxy")), + ("author", models.ForeignKey("thirdapp.AuthorProxy", models.CASCADE)), ("title", models.CharField(max_length=200)), ]) book_migrations_fk = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.UnmigratedModel")), + ("author", models.ForeignKey("migrations.UnmigratedModel", models.CASCADE)), ("title", models.CharField(max_length=200)), ]) book_with_no_author = ModelState("otherapp", "Book", [ @@ -320,12 +320,12 @@ class AutodetectorTests(TestCase): ]) book_with_author_renamed = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Writer")), + ("author", models.ForeignKey("testapp.Writer", models.CASCADE)), ("title", models.CharField(max_length=200)), ]) book_with_field_and_author_renamed = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("writer", models.ForeignKey("testapp.Writer")), + ("writer", models.ForeignKey("testapp.Writer", models.CASCADE)), ("title", models.CharField(max_length=200)), ]) book_with_multiple_authors = ModelState("otherapp", "Book", [ @@ -340,7 +340,7 @@ class AutodetectorTests(TestCase): ]) book_foo_together = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("title", models.CharField(max_length=200)), ], { "index_together": {("author", "title")}, @@ -348,7 +348,7 @@ class AutodetectorTests(TestCase): }) book_foo_together_2 = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("title", models.CharField(max_length=200)), ], { "index_together": {("title", "author")}, @@ -357,7 +357,7 @@ class AutodetectorTests(TestCase): book_foo_together_3 = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), ("newfield", models.IntegerField()), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("title", models.CharField(max_length=200)), ], { "index_together": {("title", "newfield")}, @@ -366,7 +366,7 @@ class AutodetectorTests(TestCase): book_foo_together_4 = ModelState("otherapp", "Book", [ ("id", models.AutoField(primary_key=True)), ("newfield2", models.IntegerField()), - ("author", models.ForeignKey("testapp.Author")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), ("title", models.CharField(max_length=200)), ], { "index_together": {("title", "newfield2")}, @@ -374,12 +374,12 @@ class AutodetectorTests(TestCase): }) attribution = ModelState("otherapp", "Attribution", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author")), - ("book", models.ForeignKey("otherapp.Book")), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), ]) edition = ModelState("thirdapp", "Edition", [ ("id", models.AutoField(primary_key=True)), - ("book", models.ForeignKey("otherapp.Book")), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), ]) custom_user = ModelState("thirdapp", "CustomUser", [ ("id", models.AutoField(primary_key=True)), @@ -393,13 +393,13 @@ class AutodetectorTests(TestCase): aardvark_testapp = ModelState("testapp", "Aardvark", [("id", models.AutoField(primary_key=True))]) aardvark_based_on_author = ModelState("testapp", "Aardvark", [], bases=("testapp.Author", )) aardvark_pk_fk_author = ModelState("testapp", "Aardvark", [ - ("id", models.OneToOneField("testapp.Author", primary_key=True)), + ("id", models.OneToOneField("testapp.Author", models.CASCADE, primary_key=True)), ]) knight = ModelState("eggs", "Knight", [("id", models.AutoField(primary_key=True))]) rabbit = ModelState("eggs", "Rabbit", [ ("id", models.AutoField(primary_key=True)), - ("knight", models.ForeignKey("eggs.Knight")), - ("parent", models.ForeignKey("eggs.Rabbit")), + ("knight", models.ForeignKey("eggs.Knight", models.CASCADE)), + ("parent", models.ForeignKey("eggs.Rabbit", models.CASCADE)), ], {"unique_together": {("parent", "knight")}}) def repr_changes(self, changes, include_dependencies=False): @@ -767,7 +767,7 @@ class AutodetectorTests(TestCase): ModelState("testapp", "EntityB", [ ("id", models.AutoField(primary_key=True)), ("some_label", models.CharField(max_length=255)), - ("entity_a", models.ForeignKey("testapp.EntityA")), + ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), ]), ]) after = self.make_project_state([ @@ -776,7 +776,7 @@ class AutodetectorTests(TestCase): ]), ModelState("testapp", "RenamedEntityB", [ ("id", models.AutoField(primary_key=True)), - ("entity_a", models.ForeignKey("testapp.EntityA")), + ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), ("some_label", models.CharField(max_length=255)), ]), ]) @@ -1926,14 +1926,14 @@ class AutodetectorTests(TestCase): """ address = ModelState("a", "Address", [ ("id", models.AutoField(primary_key=True)), - ("country", models.ForeignKey("b.DeliveryCountry")), + ("country", models.ForeignKey("b.DeliveryCountry", models.CASCADE)), ]) person = ModelState("a", "Person", [ ("id", models.AutoField(primary_key=True)), ]) apackage = ModelState("b", "APackage", [ ("id", models.AutoField(primary_key=True)), - ("person", models.ForeignKey("a.Person")), + ("person", models.ForeignKey("a.Person", models.CASCADE)), ]) country = ModelState("b", "DeliveryCountry", [ ("id", models.AutoField(primary_key=True)), @@ -1958,12 +1958,12 @@ class AutodetectorTests(TestCase): """ tenant = ModelState("a", "Tenant", [ ("id", models.AutoField(primary_key=True)), - ("primary_address", models.ForeignKey("b.Address"))], + ("primary_address", models.ForeignKey("b.Address", models.CASCADE))], bases=(AbstractBaseUser, ) ) address = ModelState("b", "Address", [ ("id", models.AutoField(primary_key=True)), - ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL)), + ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)), ]) # Make state before = self.make_project_state([]) @@ -1990,11 +1990,11 @@ class AutodetectorTests(TestCase): """ address = ModelState("a", "Address", [ ("id", models.AutoField(primary_key=True)), - ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL)), + ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)), ]) tenant = ModelState("b", "Tenant", [ ("id", models.AutoField(primary_key=True)), - ("primary_address", models.ForeignKey("a.Address"))], + ("primary_address", models.ForeignKey("a.Address", models.CASCADE))], bases=(AbstractBaseUser, ) ) # Make state @@ -2021,7 +2021,7 @@ class AutodetectorTests(TestCase): """ person = ModelState("a", "Person", [ ("id", models.AutoField(primary_key=True)), - ("parent1", models.ForeignKey(settings.AUTH_USER_MODEL, related_name='children')) + ("parent1", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, related_name='children')) ]) # Make state before = self.make_project_state([]) diff --git a/tests/migrations/test_migrations/0002_second.py b/tests/migrations/test_migrations/0002_second.py index 9dd60fade2..898676c9d8 100644 --- a/tests/migrations/test_migrations/0002_second.py +++ b/tests/migrations/test_migrations/0002_second.py @@ -22,7 +22,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_conflict/0002_second.py b/tests/migrations/test_migrations_conflict/0002_second.py index c525ea08a0..e5fed5df13 100644 --- a/tests/migrations/test_migrations_conflict/0002_second.py +++ b/tests/migrations/test_migrations_conflict/0002_second.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_custom_user/0001_initial.py b/tests/migrations/test_migrations_custom_user/0001_initial.py index 3a4523277d..dd1b6bc219 100644 --- a/tests/migrations/test_migrations_custom_user/0001_initial.py +++ b/tests/migrations/test_migrations_custom_user/0001_initial.py @@ -24,7 +24,7 @@ class Migration(migrations.Migration): "Tribble", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey(to=settings.AUTH_USER_MODEL, to_field="id")), + ("author", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, to_field="id")), ], ) diff --git a/tests/migrations/test_migrations_fake_split_initial/0002_second.py b/tests/migrations/test_migrations_fake_split_initial/0002_second.py index 786b77a654..6730f1c65a 100644 --- a/tests/migrations/test_migrations_fake_split_initial/0002_second.py +++ b/tests/migrations/test_migrations_fake_split_initial/0002_second.py @@ -18,7 +18,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ), ] diff --git a/tests/migrations/test_migrations_first/second.py b/tests/migrations/test_migrations_first/second.py index e85828856d..d0929e6a6f 100644 --- a/tests/migrations/test_migrations_first/second.py +++ b/tests/migrations/test_migrations_first/second.py @@ -23,7 +23,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py b/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py index e5909bd08b..3e8b270599 100644 --- a/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py +++ b/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py @@ -21,7 +21,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_no_ancestor/0002_second.py b/tests/migrations/test_migrations_no_ancestor/0002_second.py index 9dd60fade2..898676c9d8 100644 --- a/tests/migrations/test_migrations_no_ancestor/0002_second.py +++ b/tests/migrations/test_migrations_no_ancestor/0002_second.py @@ -22,7 +22,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_no_changes/0002_second.py b/tests/migrations/test_migrations_no_changes/0002_second.py index 9dd60fade2..898676c9d8 100644 --- a/tests/migrations/test_migrations_no_changes/0002_second.py +++ b/tests/migrations/test_migrations_no_changes/0002_second.py @@ -22,7 +22,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_run_before/0002_second.py b/tests/migrations/test_migrations_run_before/0002_second.py index c0e03b4620..6f1fbdd6a1 100644 --- a/tests/migrations/test_migrations_run_before/0002_second.py +++ b/tests/migrations/test_migrations_run_before/0002_second.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_squashed/0001_squashed_0002.py b/tests/migrations/test_migrations_squashed/0001_squashed_0002.py index a5f591cbf7..3b87c54da4 100644 --- a/tests/migrations/test_migrations_squashed/0001_squashed_0002.py +++ b/tests/migrations/test_migrations_squashed/0001_squashed_0002.py @@ -28,7 +28,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ), diff --git a/tests/migrations/test_migrations_squashed/0002_second.py b/tests/migrations/test_migrations_squashed/0002_second.py index c525ea08a0..e5fed5df13 100644 --- a/tests/migrations/test_migrations_squashed/0002_second.py +++ b/tests/migrations/test_migrations_squashed/0002_second.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", null=True)), + ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_migrations_unmigdep/0001_initial.py b/tests/migrations/test_migrations_unmigdep/0001_initial.py index 6503f9f05b..a47805bf68 100644 --- a/tests/migrations/test_migrations_unmigdep/0001_initial.py +++ b/tests/migrations/test_migrations_unmigdep/0001_initial.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("user", models.ForeignKey("auth.User", null=True)), + ("user", models.ForeignKey("auth.User", models.SET_NULL, null=True)), ], ) diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index de5cf5813c..79d2106c7e 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -111,8 +111,8 @@ class OperationTestBase(MigrationTestBase): "Rider", [ ("id", models.AutoField(primary_key=True)), - ("pony", models.ForeignKey("Pony")), - ("friend", models.ForeignKey("self")) + ("pony", models.ForeignKey("Pony", models.CASCADE)), + ("friend", models.ForeignKey("self", models.CASCADE)) ], )) if mti_model: @@ -120,11 +120,12 @@ class OperationTestBase(MigrationTestBase): "ShetlandPony", fields=[ ('pony_ptr', models.OneToOneField( + 'Pony', + models.CASCADE, auto_created=True, primary_key=True, to_field='id', serialize=False, - to='Pony', )), ("cuteness", models.IntegerField(default=1)), ], @@ -215,7 +216,7 @@ class OperationTests(OperationTestBase): [ ("id", models.AutoField(primary_key=True)), ("number", models.IntegerField(default=1)), - ("pony", models.ForeignKey("test_crmoua.Pony")), + ("pony", models.ForeignKey("test_crmoua.Pony", models.CASCADE)), ], ) operation3 = migrations.AlterUniqueTogether( @@ -290,11 +291,12 @@ class OperationTests(OperationTestBase): "ShetlandPony", [ ('pony_ptr', models.OneToOneField( + 'test_crmoih.Pony', + models.CASCADE, auto_created=True, primary_key=True, to_field='id', serialize=False, - to='test_crmoih.Pony', )), ("cuteness", models.IntegerField(default=1)), ], @@ -934,8 +936,8 @@ class OperationTests(OperationTestBase): self.assertTableNotExists("test_rmflmmwt_ponystables") project_state = self.apply_operations("test_rmflmmwt", project_state, operations=[ migrations.CreateModel("PonyStables", fields=[ - ("pony", models.ForeignKey('test_rmflmmwt.Pony')), - ("stable", models.ForeignKey('test_rmflmmwt.Stable')), + ("pony", models.ForeignKey('test_rmflmmwt.Pony', models.CASCADE)), + ("stable", models.ForeignKey('test_rmflmmwt.Stable', models.CASCADE)), ]), migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies", through='test_rmflmmwt.PonyStables')) ]) @@ -1414,7 +1416,7 @@ class OperationTests(OperationTestBase): name="Rider", fields=[ ("id", models.AutoField(primary_key=True)), - ("pony", models.ForeignKey(to="Pony")), + ("pony", models.ForeignKey("Pony", models.CASCADE)), ], ) create_state = project_state.clone() @@ -1422,7 +1424,7 @@ class OperationTests(OperationTestBase): alter_operation = migrations.AlterField( model_name='Rider', name='pony', - field=models.ForeignKey(editable=False, to="Pony"), + field=models.ForeignKey("Pony", models.CASCADE, editable=False), ) alter_state = create_state.clone() alter_operation.state_forwards("test_alfk", alter_state) @@ -1754,7 +1756,7 @@ class OperationTests(OperationTestBase): [ ("id", models.AutoField(primary_key=True)), ("title", models.CharField(max_length=100)), - ("author", models.ForeignKey("test_authors.Author")) + ("author", models.ForeignKey("test_authors.Author", models.CASCADE)) ], options={}, ) diff --git a/tests/migrations/test_optimizer.py b/tests/migrations/test_optimizer.py index dccb783ac7..52a26013ec 100644 --- a/tests/migrations/test_optimizer.py +++ b/tests/migrations/test_optimizer.py @@ -198,12 +198,12 @@ class OptimizerTests(SimpleTestCase): self.assertOptimizesTo( [ migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo"))]), + migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]), migrations.DeleteModel("Foo"), ], [ migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo"))]), + migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]), migrations.DeleteModel("Foo"), ], ) @@ -260,12 +260,12 @@ class OptimizerTests(SimpleTestCase): [ migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Link", [("url", models.TextField())]), - migrations.AddField("Foo", "link", models.ForeignKey("migrations.Link")), + migrations.AddField("Foo", "link", models.ForeignKey("migrations.Link", models.CASCADE)), ], [ migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Link", [("url", models.TextField())]), - migrations.AddField("Foo", "link", models.ForeignKey("migrations.Link")), + migrations.AddField("Foo", "link", models.ForeignKey("migrations.Link", models.CASCADE)), ], ) diff --git a/tests/migrations/test_state.py b/tests/migrations/test_state.py index 0189d35d82..3d059b32cb 100644 --- a/tests/migrations/test_state.py +++ b/tests/migrations/test_state.py @@ -56,7 +56,7 @@ class StateTests(SimpleTestCase): class Book(models.Model): title = models.CharField(max_length=1000) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) contributors = models.ManyToManyField(Author) class Meta: @@ -222,11 +222,12 @@ class StateTests(SimpleTestCase): name="SubTag", fields=[ ('tag_ptr', models.OneToOneField( + 'migrations.Tag', + models.CASCADE, auto_created=True, primary_key=True, to_field='id', serialize=False, - to='migrations.Tag', )), ("awesome", models.BooleanField()), ], @@ -449,7 +450,11 @@ class StateTests(SimpleTestCase): self.assertIs(model_a_old._meta.get_field('b').related_model, model_b_old) self.assertIs(model_b_old._meta.get_field('a_ptr').related_model, model_a_old) - operation = AddField('c', 'to_a', models.OneToOneField('something.A', related_name='from_c')) + operation = AddField('c', 'to_a', models.OneToOneField( + 'something.A', + models.CASCADE, + related_name='from_c', + )) operation.state_forwards('something', project_state) model_a_new = project_state.apps.get_model('something', 'A') model_b_new = project_state.apps.get_model('something', 'B') @@ -481,7 +486,7 @@ class StateTests(SimpleTestCase): apps = new_apps class B(models.Model): - to_a = models.ForeignKey(A) + to_a = models.ForeignKey(A, models.CASCADE) class Meta: app_label = "something" @@ -621,7 +626,7 @@ class StateTests(SimpleTestCase): apps = new_apps class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) class Meta: app_label = "migrations" @@ -661,7 +666,7 @@ class StateTests(SimpleTestCase): new_apps = Apps() class TestModel(models.Model): - ct = models.ForeignKey("contenttypes.ContentType") + ct = models.ForeignKey("contenttypes.ContentType", models.CASCADE) class Meta: app_label = "migrations" @@ -697,7 +702,7 @@ class StateTests(SimpleTestCase): apps = new_apps class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) class Meta: app_label = "migrations" @@ -784,7 +789,7 @@ class ModelStateTests(SimpleTestCase): ModelState('app', 'Model', [('field', field)]) def test_sanity_check_to(self): - field = models.ForeignKey(UnicodeModel) + field = models.ForeignKey(UnicodeModel, models.CASCADE) with self.assertRaisesMessage(ValueError, 'ModelState.fields cannot refer to a model class - "field.to" does. ' 'Use a string reference instead.'): @@ -911,35 +916,35 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(B, []) def test_direct_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) B = self.create_model("B") self.assertRelated(A, [B]) self.assertRelated(B, [A]) def test_direct_hidden_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', related_name='+')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE, related_name='+')]) B = self.create_model("B") self.assertRelated(A, [B]) self.assertRelated(B, [A]) def test_nested_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B')]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('C')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) + B = self.create_model("B", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) C = self.create_model("C") self.assertRelated(A, [B, C]) self.assertRelated(B, [A, C]) self.assertRelated(C, [A, B]) def test_two_sided(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B')]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('A')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) + B = self.create_model("B", foreign_keys=[models.ForeignKey('A', models.CASCADE)]) self.assertRelated(A, [B]) self.assertRelated(B, [A]) def test_circle(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B')]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('C')]) - C = self.create_model("C", foreign_keys=[models.ForeignKey('A')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) + B = self.create_model("B", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) + C = self.create_model("C", foreign_keys=[models.ForeignKey('A', models.CASCADE)]) self.assertRelated(A, [B, C]) self.assertRelated(B, [A, C]) self.assertRelated(C, [A, B]) @@ -985,7 +990,7 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(Z, [Y]) def test_base_to_base_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('Y')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('Y', models.CASCADE)]) B = self.create_model("B", bases=(A,)) Y = self.create_model("Y") Z = self.create_model("Z", bases=(Y,)) @@ -995,7 +1000,7 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(Z, [A, B, Y]) def test_base_to_subclass_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('Z')]) + A = self.create_model("A", foreign_keys=[models.ForeignKey('Z', models.CASCADE)]) B = self.create_model("B", bases=(A,)) Y = self.create_model("Y") Z = self.create_model("Z", bases=(Y,)) @@ -1016,14 +1021,20 @@ class RelatedModelsTests(SimpleTestCase): def test_intermediate_m2m_self(self): A = self.create_model("A", foreign_keys=[models.ManyToManyField('A', through='T')]) - T = self.create_model("T", foreign_keys=[models.ForeignKey('A'), models.ForeignKey('A')]) + T = self.create_model("T", foreign_keys=[ + models.ForeignKey('A', models.CASCADE), + models.ForeignKey('A', models.CASCADE), + ]) self.assertRelated(A, [T]) self.assertRelated(T, [A]) def test_intermediate_m2m(self): A = self.create_model("A", foreign_keys=[models.ManyToManyField('B', through='T')]) B = self.create_model("B") - T = self.create_model("T", foreign_keys=[models.ForeignKey('A'), models.ForeignKey('B')]) + T = self.create_model("T", foreign_keys=[ + models.ForeignKey('A', models.CASCADE), + models.ForeignKey('B', models.CASCADE), + ]) self.assertRelated(A, [B, T]) self.assertRelated(B, [A, T]) self.assertRelated(T, [A, B]) @@ -1033,7 +1044,9 @@ class RelatedModelsTests(SimpleTestCase): B = self.create_model("B") Z = self.create_model("Z") T = self.create_model("T", foreign_keys=[ - models.ForeignKey('A'), models.ForeignKey('B'), models.ForeignKey('Z'), + models.ForeignKey('A', models.CASCADE), + models.ForeignKey('B', models.CASCADE), + models.ForeignKey('Z', models.CASCADE), ]) self.assertRelated(A, [B, T, Z]) self.assertRelated(B, [A, T, Z]) @@ -1044,15 +1057,23 @@ class RelatedModelsTests(SimpleTestCase): A = self.create_model("A", foreign_keys=[models.ManyToManyField('B', through='T')]) B = self.create_model("B") S = self.create_model("S") - T = self.create_model("T", foreign_keys=[models.ForeignKey('A'), models.ForeignKey('B')], bases=(S,)) + T = self.create_model("T", foreign_keys=[ + models.ForeignKey('A', models.CASCADE), + models.ForeignKey('B', models.CASCADE), + ], bases=(S,)) self.assertRelated(A, [B, S, T]) self.assertRelated(B, [A, S, T]) self.assertRelated(S, [A, B, T]) self.assertRelated(T, [A, B, S]) def test_generic_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B'), GenericForeignKey()]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('C')]) + A = self.create_model("A", foreign_keys=[ + models.ForeignKey('B', models.CASCADE), + GenericForeignKey(), + ]) + B = self.create_model("B", foreign_keys=[ + models.ForeignKey('C', models.CASCADE), + ]) self.assertRelated(A, [B]) self.assertRelated(B, [A]) diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index a836cbb97e..0f2e54f939 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -31,7 +31,7 @@ def get_foo(): class Bar(models.Model): b = models.CharField(max_length=10) - a = models.ForeignKey(Foo, default=get_foo, related_name=b'bars') + a = models.ForeignKey(Foo, models.CASCADE, default=get_foo, related_name=b'bars') class Whiz(models.Model): @@ -145,13 +145,13 @@ class PrimaryKeyCharModel(models.Model): class FksToBooleans(models.Model): """Model with FKs to models with {Null,}BooleanField's, #15040""" - bf = models.ForeignKey(BooleanModel) - nbf = models.ForeignKey(NullBooleanModel) + bf = models.ForeignKey(BooleanModel, models.CASCADE) + nbf = models.ForeignKey(NullBooleanModel, models.CASCADE) class FkToChar(models.Model): """Model with FK to a model with a CharField primary key, #19299""" - out = models.ForeignKey(PrimaryKeyCharModel) + out = models.ForeignKey(PrimaryKeyCharModel, models.CASCADE) class RenamedField(models.Model): @@ -343,19 +343,21 @@ class AllFieldsModel(models.Model): fo = ForeignObject( 'self', + on_delete=models.CASCADE, from_fields=['abstract_non_concrete_id'], to_fields=['id'], related_name='reverse' ) fk = ForeignKey( 'self', + models.CASCADE, related_name='reverse2' ) m2m = ManyToManyField('self') - oto = OneToOneField('self') + oto = OneToOneField('self', models.CASCADE) object_id = models.PositiveIntegerField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) gfk = GenericForeignKey() gr = GenericRelation(DataModel) @@ -376,7 +378,7 @@ class PrimaryKeyUUIDModel(models.Model): class RelatedToUUIDModel(models.Model): - uuid_fk = models.ForeignKey('PrimaryKeyUUIDModel') + uuid_fk = models.ForeignKey('PrimaryKeyUUIDModel', models.CASCADE) class UUIDChild(PrimaryKeyUUIDModel): diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py index 8bbead1a36..128bdb25af 100644 --- a/tests/model_fields/tests.py +++ b/tests/model_fields/tests.py @@ -187,7 +187,7 @@ class ForeignKeyTests(test.TestCase): def test_warning_when_unique_true_on_fk(self): class FKUniqueTrue(models.Model): - fk_field = models.ForeignKey(Foo, unique=True) + fk_field = models.ForeignKey(Foo, models.CASCADE, unique=True) model = FKUniqueTrue() expected_warnings = [ @@ -213,7 +213,7 @@ class ForeignKeyTests(test.TestCase): pending_ops_before = list(apps._pending_operations.items()) class AbstractForeignKeyModel(models.Model): - fk = models.ForeignKey('missing.FK') + fk = models.ForeignKey('missing.FK', models.CASCADE) class Meta: abstract = True @@ -235,7 +235,7 @@ class ManyToManyFieldTests(test.SimpleTestCase): pending_ops_before = list(apps._pending_operations.items()) class AbstractManyToManyModel(models.Model): - fk = models.ForeignKey('missing.FK') + fk = models.ForeignKey('missing.FK', models.CASCADE) class Meta: abstract = True diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py index 08b0c96ac5..f7dca5bb77 100644 --- a/tests/model_forms/models.py +++ b/tests/model_forms/models.py @@ -71,7 +71,7 @@ class Article(models.Model): slug = models.SlugField() pub_date = models.DateField() created = models.DateField(editable=False) - writer = models.ForeignKey(Writer) + writer = models.ForeignKey(Writer, models.CASCADE) article = models.TextField() categories = models.ManyToManyField(Category, blank=True) status = models.PositiveIntegerField(choices=ARTICLE_STATUS, blank=True, null=True) @@ -86,11 +86,11 @@ class Article(models.Model): class ImprovedArticle(models.Model): - article = models.OneToOneField(Article) + article = models.OneToOneField(Article, models.CASCADE) class ImprovedArticleWithParentLink(models.Model): - article = models.OneToOneField(Article, parent_link=True) + article = models.OneToOneField(Article, models.CASCADE, parent_link=True) class BetterWriter(Writer): @@ -124,18 +124,18 @@ class PublicationDefaults(models.Model): class Author(models.Model): - publication = models.OneToOneField(Publication, null=True, blank=True) + publication = models.OneToOneField(Publication, models.SET_NULL, null=True, blank=True) full_name = models.CharField(max_length=255) class Author1(models.Model): - publication = models.OneToOneField(Publication, null=False) + publication = models.OneToOneField(Publication, models.SET_NULL, null=False) full_name = models.CharField(max_length=255) @python_2_unicode_compatible class WriterProfile(models.Model): - writer = models.OneToOneField(Writer, primary_key=True) + writer = models.OneToOneField(Writer, models.CASCADE, primary_key=True) age = models.PositiveIntegerField() def __str__(self): @@ -262,7 +262,7 @@ class ArticleStatus(models.Model): @python_2_unicode_compatible class Inventory(models.Model): barcode = models.PositiveIntegerField(unique=True) - parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) + parent = models.ForeignKey('self', models.SET_NULL, to_field='barcode', blank=True, null=True) name = models.CharField(blank=False, max_length=20) class Meta: @@ -277,7 +277,7 @@ class Inventory(models.Model): class Book(models.Model): title = models.CharField(max_length=40) - author = models.ForeignKey(Writer, blank=True, null=True) + author = models.ForeignKey(Writer, models.SET_NULL, blank=True, null=True) special_id = models.IntegerField(blank=True, null=True, unique=True) class Meta: @@ -418,13 +418,18 @@ class Character(models.Model): class StumpJoke(models.Model): - most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+") + most_recently_fooled = models.ForeignKey( + Character, + models.CASCADE, + limit_choices_to=today_callable_dict, + related_name="+", + ) has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+") # Model for #13776 class Student(models.Model): - character = models.ForeignKey(Character) + character = models.ForeignKey(Character, models.CASCADE) study = models.CharField(max_length=30) diff --git a/tests/model_formsets/models.py b/tests/model_formsets/models.py index 18b2525738..df6a68792b 100644 --- a/tests/model_formsets/models.py +++ b/tests/model_formsets/models.py @@ -25,7 +25,7 @@ class BetterAuthor(Author): @python_2_unicode_compatible class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=100) class Meta: @@ -41,7 +41,7 @@ class Book(models.Model): @python_2_unicode_compatible class BookWithCustomPK(models.Model): my_pk = models.DecimalField(max_digits=5, decimal_places=0, primary_key=True) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=100) def __str__(self): @@ -54,9 +54,9 @@ class Editor(models.Model): @python_2_unicode_compatible class BookWithOptionalAltEditor(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) # Optional secondary author - alt_editor = models.ForeignKey(Editor, blank=True, null=True) + alt_editor = models.ForeignKey(Editor, models.SET_NULL, blank=True, null=True) title = models.CharField(max_length=100) class Meta: @@ -107,14 +107,14 @@ class Place(models.Model): class Owner(models.Model): auto_id = models.AutoField(primary_key=True) name = models.CharField(max_length=100) - place = models.ForeignKey(Place) + place = models.ForeignKey(Place, models.CASCADE) def __str__(self): return "%s at %s" % (self.name, self.place) class Location(models.Model): - place = models.ForeignKey(Place, unique=True) + place = models.ForeignKey(Place, models.CASCADE, unique=True) # this is purely for testing the data doesn't matter here :) lat = models.CharField(max_length=100) lon = models.CharField(max_length=100) @@ -122,7 +122,7 @@ class Location(models.Model): @python_2_unicode_compatible class OwnerProfile(models.Model): - owner = models.OneToOneField(Owner, primary_key=True) + owner = models.OneToOneField(Owner, models.CASCADE, primary_key=True) age = models.PositiveIntegerField() def __str__(self): @@ -162,7 +162,7 @@ class MexicanRestaurant(Restaurant): class ClassyMexicanRestaurant(MexicanRestaurant): - restaurant = models.OneToOneField(MexicanRestaurant, parent_link=True, primary_key=True) + restaurant = models.OneToOneField(MexicanRestaurant, models.CASCADE, parent_link=True, primary_key=True) tacos_are_yummy = models.BooleanField(default=False) @@ -178,7 +178,7 @@ class Repository(models.Model): @python_2_unicode_compatible class Revision(models.Model): - repository = models.ForeignKey(Repository) + repository = models.ForeignKey(Repository, models.CASCADE) revision = models.CharField(max_length=40) class Meta: @@ -196,7 +196,7 @@ class Person(models.Model): class Membership(models.Model): - person = models.ForeignKey(Person) + person = models.ForeignKey(Person, models.CASCADE) date_joined = models.DateTimeField(default=datetime.datetime.now) karma = models.IntegerField() @@ -208,7 +208,7 @@ class Team(models.Model): @python_2_unicode_compatible class Player(models.Model): - team = models.ForeignKey(Team, null=True) + team = models.ForeignKey(Team, models.SET_NULL, null=True) name = models.CharField(max_length=100) def __str__(self): @@ -226,7 +226,7 @@ class Poet(models.Model): @python_2_unicode_compatible class Poem(models.Model): - poet = models.ForeignKey(Poet) + poet = models.ForeignKey(Poet, models.CASCADE) name = models.CharField(max_length=100) def __str__(self): @@ -253,17 +253,17 @@ class UUIDPKParent(models.Model): class UUIDPKChild(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) - parent = models.ForeignKey(UUIDPKParent) + parent = models.ForeignKey(UUIDPKParent, models.CASCADE) class ChildWithEditablePK(models.Model): name = models.CharField(max_length=255, primary_key=True) - parent = models.ForeignKey(UUIDPKParent) + parent = models.ForeignKey(UUIDPKParent, models.CASCADE) class AutoPKChildOfUUIDPKParent(models.Model): name = models.CharField(max_length=255) - parent = models.ForeignKey(UUIDPKParent) + parent = models.ForeignKey(UUIDPKParent, models.CASCADE) class AutoPKParent(models.Model): @@ -273,7 +273,7 @@ class AutoPKParent(models.Model): class UUIDPKChildOfAutoPKParent(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) - parent = models.ForeignKey(AutoPKParent) + parent = models.ForeignKey(AutoPKParent, models.CASCADE) class ParentWithUUIDAlternateKey(models.Model): @@ -283,4 +283,4 @@ class ParentWithUUIDAlternateKey(models.Model): class ChildRelatedViaAK(models.Model): name = models.CharField(max_length=255) - parent = models.ForeignKey(to=ParentWithUUIDAlternateKey, to_field='uuid') + parent = models.ForeignKey(ParentWithUUIDAlternateKey, models.CASCADE, to_field='uuid') diff --git a/tests/model_formsets_regress/models.py b/tests/model_formsets_regress/models.py index c9ded9e761..064cddd4a0 100644 --- a/tests/model_formsets_regress/models.py +++ b/tests/model_formsets_regress/models.py @@ -8,17 +8,17 @@ class User(models.Model): class UserSite(models.Model): - user = models.ForeignKey(User, to_field="username") + user = models.ForeignKey(User, models.CASCADE, to_field="username") data = models.IntegerField() class UserProfile(models.Model): - user = models.ForeignKey(User, unique=True, to_field="username") + user = models.ForeignKey(User, models.CASCADE, unique=True, to_field="username") about = models.TextField() class ProfileNetwork(models.Model): - profile = models.ForeignKey(UserProfile, to_field="user") + profile = models.ForeignKey(UserProfile, models.CASCADE, to_field="user") network = models.IntegerField() identifier = models.IntegerField() @@ -32,7 +32,7 @@ class Restaurant(Place): class Manager(models.Model): - restaurant = models.ForeignKey(Restaurant) + restaurant = models.ForeignKey(Restaurant, models.CASCADE) name = models.CharField(max_length=50) @@ -42,7 +42,7 @@ class Network(models.Model): @python_2_unicode_compatible class Host(models.Model): - network = models.ForeignKey(Network) + network = models.ForeignKey(Network, models.CASCADE) hostname = models.CharField(max_length=25) def __str__(self): diff --git a/tests/model_inheritance/models.py b/tests/model_inheritance/models.py index a77ab15f70..22086ca11d 100644 --- a/tests/model_inheritance/models.py +++ b/tests/model_inheritance/models.py @@ -56,7 +56,7 @@ class Post(models.Model): @python_2_unicode_compatible class Attachment(models.Model): - post = models.ForeignKey(Post, related_name='attached_%(class)s_set') + post = models.ForeignKey(Post, models.CASCADE, related_name='attached_%(class)s_set') content = models.TextField() class Meta: @@ -107,7 +107,7 @@ class Rating(models.Model): class Restaurant(Place, Rating): serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) - chef = models.ForeignKey(Chef, null=True, blank=True) + chef = models.ForeignKey(Chef, models.SET_NULL, null=True, blank=True) class Meta(Rating.Meta): db_table = 'my_restaurant' @@ -135,8 +135,8 @@ class Supplier(Place): @python_2_unicode_compatible class ParkingLot(Place): # An explicit link to the parent (we can control the attribute name). - parent = models.OneToOneField(Place, primary_key=True, parent_link=True) - main_site = models.ForeignKey(Place, related_name='lot') + parent = models.OneToOneField(Place, models.CASCADE, primary_key=True, parent_link=True) + main_site = models.ForeignKey(Place, models.CASCADE, related_name='lot') def __str__(self): return "%s the parking lot" % self.name @@ -156,7 +156,7 @@ class Title(models.Model): class NamedURL(models.Model): - title = models.ForeignKey(Title, related_name='attached_%(app_label)s_%(class)s_set') + title = models.ForeignKey(Title, models.CASCADE, related_name='attached_%(app_label)s_%(class)s_set') url = models.URLField() class Meta: diff --git a/tests/model_inheritance_regress/models.py b/tests/model_inheritance_regress/models.py index 48adf94ddf..ad905db981 100644 --- a/tests/model_inheritance_regress/models.py +++ b/tests/model_inheritance_regress/models.py @@ -38,7 +38,7 @@ class ItalianRestaurant(Restaurant): @python_2_unicode_compatible class ParkingLot(Place): # An explicit link to the parent (we can control the attribute name). - parent = models.OneToOneField(Place, primary_key=True, parent_link=True) + parent = models.OneToOneField(Place, models.CASCADE, primary_key=True, parent_link=True) capacity = models.IntegerField() def __str__(self): @@ -48,18 +48,18 @@ class ParkingLot(Place): class ParkingLot2(Place): # In lieu of any other connector, an existing OneToOneField will be # promoted to the primary key. - parent = models.OneToOneField(Place) + parent = models.OneToOneField(Place, models.CASCADE) class ParkingLot3(Place): # The parent_link connector need not be the pk on the model. primary_key = models.AutoField(primary_key=True) - parent = models.OneToOneField(Place, parent_link=True) + parent = models.OneToOneField(Place, models.CASCADE, parent_link=True) class ParkingLot4(models.Model): # Test parent_link connector can be discovered in abstract classes. - parent = models.OneToOneField(Place, parent_link=True) + parent = models.OneToOneField(Place, models.CASCADE, parent_link=True) class Meta: abstract = True @@ -76,14 +76,14 @@ class ParkingLot4B(Place, ParkingLot4): @python_2_unicode_compatible class Supplier(models.Model): name = models.CharField(max_length=50) - restaurant = models.ForeignKey(Restaurant) + restaurant = models.ForeignKey(Restaurant, models.CASCADE) def __str__(self): return self.name class Wholesaler(Supplier): - retailer = models.ForeignKey(Supplier, related_name='wholesale_supplier') + retailer = models.ForeignKey(Supplier, models.CASCADE, related_name='wholesale_supplier') class Parent(models.Model): @@ -96,7 +96,7 @@ class Child(Parent): class SelfRefParent(models.Model): parent_data = models.IntegerField() - self_data = models.ForeignKey('self', null=True) + self_data = models.ForeignKey('self', models.SET_NULL, null=True) class SelfRefChild(SelfRefParent): diff --git a/tests/model_meta/models.py b/tests/model_meta/models.py index 6ce36ed9d6..5189543880 100644 --- a/tests/model_meta/models.py +++ b/tests/model_meta/models.py @@ -12,7 +12,7 @@ class Relation(models.Model): class AbstractPerson(models.Model): # DATA fields data_abstract = models.CharField(max_length=10) - fk_abstract = models.ForeignKey(Relation, related_name='fk_abstract_rel') + fk_abstract = models.ForeignKey(Relation, models.CASCADE, related_name='fk_abstract_rel') # M2M fields m2m_abstract = models.ManyToManyField(Relation, related_name='m2m_abstract_rel') @@ -22,13 +22,14 @@ class AbstractPerson(models.Model): # VIRTUAL fields data_not_concrete_abstract = models.ForeignObject( Relation, + on_delete=models.CASCADE, from_fields=['abstract_non_concrete_id'], to_fields=['id'], related_name='fo_abstract_rel', ) # GFK fields - content_type_abstract = models.ForeignKey(ContentType, related_name='+') + content_type_abstract = models.ForeignKey(ContentType, models.CASCADE, related_name='+') object_id_abstract = models.PositiveIntegerField() content_object_abstract = GenericForeignKey('content_type_abstract', 'object_id_abstract') @@ -42,7 +43,7 @@ class AbstractPerson(models.Model): class BasePerson(AbstractPerson): # DATA fields data_base = models.CharField(max_length=10) - fk_base = models.ForeignKey(Relation, related_name='fk_base_rel') + fk_base = models.ForeignKey(Relation, models.CASCADE, related_name='fk_base_rel') # M2M fields m2m_base = models.ManyToManyField(Relation, related_name='m2m_base_rel') @@ -52,13 +53,14 @@ class BasePerson(AbstractPerson): # VIRTUAL fields data_not_concrete_base = models.ForeignObject( Relation, + on_delete=models.CASCADE, from_fields=['base_non_concrete_id'], to_fields=['id'], related_name='fo_base_rel', ) # GFK fields - content_type_base = models.ForeignKey(ContentType, related_name='+') + content_type_base = models.ForeignKey(ContentType, models.CASCADE, related_name='+') object_id_base = models.PositiveIntegerField() content_object_base = GenericForeignKey('content_type_base', 'object_id_base') @@ -69,7 +71,7 @@ class BasePerson(AbstractPerson): class Person(BasePerson): # DATA fields data_inherited = models.CharField(max_length=10) - fk_inherited = models.ForeignKey(Relation, related_name='fk_concrete_rel') + fk_inherited = models.ForeignKey(Relation, models.CASCADE, related_name='fk_concrete_rel') # M2M Fields m2m_inherited = models.ManyToManyField(Relation, related_name='m2m_concrete_rel') @@ -79,13 +81,14 @@ class Person(BasePerson): # VIRTUAL fields data_not_concrete_inherited = models.ForeignObject( Relation, + on_delete=models.CASCADE, from_fields=['model_non_concrete_id'], to_fields=['id'], related_name='fo_concrete_rel', ) # GFK fields - content_type_concrete = models.ForeignKey(ContentType, related_name='+') + content_type_concrete = models.ForeignKey(ContentType, models.CASCADE, related_name='+') object_id_concrete = models.PositiveIntegerField() content_object_concrete = GenericForeignKey('content_type_concrete', 'object_id_concrete') @@ -101,16 +104,16 @@ class ProxyPerson(Person): class Relating(models.Model): # ForeignKey to BasePerson - baseperson = models.ForeignKey(BasePerson, related_name='relating_baseperson') - baseperson_hidden = models.ForeignKey(BasePerson, related_name='+') + baseperson = models.ForeignKey(BasePerson, models.CASCADE, related_name='relating_baseperson') + baseperson_hidden = models.ForeignKey(BasePerson, models.CASCADE, related_name='+') # ForeignKey to Person - person = models.ForeignKey(Person, related_name='relating_person') - person_hidden = models.ForeignKey(Person, related_name='+') + person = models.ForeignKey(Person, models.CASCADE, related_name='relating_person') + person_hidden = models.ForeignKey(Person, models.CASCADE, related_name='+') # ForeignKey to ProxyPerson - proxyperson = models.ForeignKey(ProxyPerson, related_name='relating_proxyperson') - proxyperson_hidden = models.ForeignKey(ProxyPerson, related_name='+') + proxyperson = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='relating_proxyperson') + proxyperson_hidden = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='+') # ManyToManyField to BasePerson basepeople = models.ManyToManyField(BasePerson, related_name='relating_basepeople') @@ -127,11 +130,11 @@ class CommonAncestor(models.Model): class FirstParent(CommonAncestor): - first_ancestor = models.OneToOneField(CommonAncestor, primary_key=True, parent_link=True) + first_ancestor = models.OneToOneField(CommonAncestor, models.SET_NULL, primary_key=True, parent_link=True) class SecondParent(CommonAncestor): - second_ancestor = models.OneToOneField(CommonAncestor, primary_key=True, parent_link=True) + second_ancestor = models.OneToOneField(CommonAncestor, models.SET_NULL, primary_key=True, parent_link=True) class Child(FirstParent, SecondParent): diff --git a/tests/model_options/models/default_related_name.py b/tests/model_options/models/default_related_name.py index 57b52647e6..d4687dc6a2 100644 --- a/tests/model_options/models/default_related_name.py +++ b/tests/model_options/models/default_related_name.py @@ -8,13 +8,13 @@ class Author(models.Model): class Editor(models.Model): name = models.CharField(max_length=128) - bestselling_author = models.ForeignKey(Author) + bestselling_author = models.ForeignKey(Author, models.CASCADE) class Book(models.Model): title = models.CharField(max_length=128) authors = models.ManyToManyField(Author) - editor = models.ForeignKey(Editor, related_name="edited_books") + editor = models.ForeignKey(Editor, models.CASCADE, related_name="edited_books") class Meta: default_related_name = "books" @@ -34,7 +34,7 @@ class BookStore(Store): class EditorStore(Store): - editor = models.ForeignKey(Editor) + editor = models.ForeignKey(Editor, models.CASCADE) available_books = models.ManyToManyField(Book) class Meta: diff --git a/tests/model_regress/models.py b/tests/model_regress/models.py index d4c769af55..e7c2b3a494 100644 --- a/tests/model_regress/models.py +++ b/tests/model_regress/models.py @@ -52,7 +52,7 @@ class Department(models.Model): @python_2_unicode_compatible class Worker(models.Model): - department = models.ForeignKey(Department) + department = models.ForeignKey(Department, models.CASCADE) name = models.CharField(max_length=200) def __str__(self): @@ -78,8 +78,8 @@ class Model1(models.Model): class Model2(models.Model): - model1 = models.ForeignKey(Model1, unique=True, to_field='pkey') + model1 = models.ForeignKey(Model1, models.CASCADE, unique=True, to_field='pkey') class Model3(models.Model): - model2 = models.ForeignKey(Model2, unique=True, to_field='model1') + model2 = models.ForeignKey(Model2, models.CASCADE, unique=True, to_field='model1') diff --git a/tests/model_validation/models.py b/tests/model_validation/models.py index dfe6d62996..0388f9508c 100644 --- a/tests/model_validation/models.py +++ b/tests/model_validation/models.py @@ -41,8 +41,8 @@ class ManyToManyRel(models.Model): class FKRel(models.Model): - thing1 = models.ForeignKey(ThingWithIterableChoices, related_name='+') - thing2 = models.ForeignKey(ThingWithIterableChoices, related_name='+') + thing1 = models.ForeignKey(ThingWithIterableChoices, models.CASCADE, related_name='+') + thing2 = models.ForeignKey(ThingWithIterableChoices, models.CASCADE, related_name='+') class Meta: # Models created as unmanaged as these aren't ever queried diff --git a/tests/modeladmin/models.py b/tests/modeladmin/models.py index 8457e60876..8f69b42874 100644 --- a/tests/modeladmin/models.py +++ b/tests/modeladmin/models.py @@ -18,8 +18,8 @@ class Band(models.Model): class Concert(models.Model): - main_band = models.ForeignKey(Band, related_name='main_concerts') - opening_band = models.ForeignKey(Band, related_name='opening_concerts', + main_band = models.ForeignKey(Band, models.CASCADE, related_name='main_concerts') + opening_band = models.ForeignKey(Band, models.CASCADE, related_name='opening_concerts', blank=True) day = models.CharField(max_length=3, choices=((1, 'Fri'), (2, 'Sat'))) transport = models.CharField(max_length=100, choices=( @@ -36,7 +36,7 @@ class ValidationTestModel(models.Model): state = models.CharField(max_length=2, choices=(("CO", "Colorado"), ("WA", "Washington"))) is_active = models.BooleanField(default=False) pub_date = models.DateTimeField() - band = models.ForeignKey(Band) + band = models.ForeignKey(Band, models.CASCADE) no = models.IntegerField(verbose_name="Number", blank=True, null=True) # This field is intentionally 2 characters long. See #16080. def decade_published_in(self): @@ -44,4 +44,4 @@ class ValidationTestModel(models.Model): class ValidationTestInlineModel(models.Model): - parent = models.ForeignKey(ValidationTestModel) + parent = models.ForeignKey(ValidationTestModel, models.CASCADE) diff --git a/tests/multiple_database/models.py b/tests/multiple_database/models.py index e5d3e723e4..367cd31d63 100644 --- a/tests/multiple_database/models.py +++ b/tests/multiple_database/models.py @@ -10,7 +10,7 @@ from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class Review(models.Model): source = models.CharField(max_length=100) - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -58,7 +58,7 @@ class Book(models.Model): title = models.CharField(max_length=100) published = models.DateField() authors = models.ManyToManyField(Person) - editor = models.ForeignKey(Person, null=True, related_name='edited') + editor = models.ForeignKey(Person, models.SET_NULL, null=True, related_name='edited') reviews = GenericRelation(Review) pages = models.IntegerField(default=100) @@ -72,7 +72,7 @@ class Book(models.Model): @python_2_unicode_compatible class Pet(models.Model): name = models.CharField(max_length=100) - owner = models.ForeignKey(Person) + owner = models.ForeignKey(Person, models.CASCADE) def __str__(self): return self.name @@ -82,7 +82,7 @@ class Pet(models.Model): class UserProfile(models.Model): - user = models.OneToOneField(User, null=True) + user = models.OneToOneField(User, models.SET_NULL, null=True) flavor = models.CharField(max_length=100) class Meta: diff --git a/tests/mutually_referential/models.py b/tests/mutually_referential/models.py index e5b5b787bf..cc1dacc118 100644 --- a/tests/mutually_referential/models.py +++ b/tests/mutually_referential/models.py @@ -11,11 +11,11 @@ class Parent(models.Model): name = models.CharField(max_length=100) # Use a simple string for forward declarations. - bestchild = models.ForeignKey("Child", null=True, related_name="favored_by") + bestchild = models.ForeignKey("Child", models.SET_NULL, null=True, related_name="favored_by") class Child(models.Model): name = models.CharField(max_length=100) # You can also explicitly specify the related app. - parent = models.ForeignKey("mutually_referential.Parent") + parent = models.ForeignKey("mutually_referential.Parent", models.CASCADE) diff --git a/tests/nested_foreign_keys/models.py b/tests/nested_foreign_keys/models.py index 3b99cfcb67..5805de5d52 100644 --- a/tests/nested_foreign_keys/models.py +++ b/tests/nested_foreign_keys/models.py @@ -7,7 +7,7 @@ class Person(models.Model): class Movie(models.Model): title = models.CharField(max_length=200) - director = models.ForeignKey(Person) + director = models.ForeignKey(Person, models.CASCADE) class Event(models.Model): @@ -15,16 +15,16 @@ class Event(models.Model): class Screening(Event): - movie = models.ForeignKey(Movie) + movie = models.ForeignKey(Movie, models.CASCADE) class ScreeningNullFK(Event): - movie = models.ForeignKey(Movie, null=True) + movie = models.ForeignKey(Movie, models.SET_NULL, null=True) class Package(models.Model): - screening = models.ForeignKey(Screening, null=True) + screening = models.ForeignKey(Screening, models.SET_NULL, null=True) class PackageNullFK(models.Model): - screening = models.ForeignKey(ScreeningNullFK, null=True) + screening = models.ForeignKey(ScreeningNullFK, models.SET_NULL, null=True) diff --git a/tests/null_fk/models.py b/tests/null_fk/models.py index 9309ae940f..6a7da8f620 100644 --- a/tests/null_fk/models.py +++ b/tests/null_fk/models.py @@ -11,18 +11,18 @@ class SystemDetails(models.Model): class SystemInfo(models.Model): - system_details = models.ForeignKey(SystemDetails) + system_details = models.ForeignKey(SystemDetails, models.CASCADE) system_name = models.CharField(max_length=32) class Forum(models.Model): - system_info = models.ForeignKey(SystemInfo) + system_info = models.ForeignKey(SystemInfo, models.CASCADE) forum_name = models.CharField(max_length=32) @python_2_unicode_compatible class Post(models.Model): - forum = models.ForeignKey(Forum, null=True) + forum = models.ForeignKey(Forum, models.SET_NULL, null=True) title = models.CharField(max_length=32) def __str__(self): @@ -31,7 +31,7 @@ class Post(models.Model): @python_2_unicode_compatible class Comment(models.Model): - post = models.ForeignKey(Post, null=True) + post = models.ForeignKey(Post, models.SET_NULL, null=True) comment_text = models.CharField(max_length=250) class Meta: @@ -52,6 +52,6 @@ class PropertyValue(models.Model): class Property(models.Model): - item = models.ForeignKey(Item, related_name='props') + item = models.ForeignKey(Item, models.CASCADE, related_name='props') key = models.CharField(max_length=100) - value = models.ForeignKey(PropertyValue, null=True) + value = models.ForeignKey(PropertyValue, models.SET_NULL, null=True) diff --git a/tests/null_fk_ordering/models.py b/tests/null_fk_ordering/models.py index dac1c4f6ae..b5d59eca0f 100644 --- a/tests/null_fk_ordering/models.py +++ b/tests/null_fk_ordering/models.py @@ -19,7 +19,7 @@ class Author(models.Model): @python_2_unicode_compatible class Article(models.Model): title = models.CharField(max_length=150) - author = models.ForeignKey(Author, null=True) + author = models.ForeignKey(Author, models.SET_NULL, null=True) def __str__(self): return 'Article titled: %s' % (self.title, ) @@ -34,13 +34,13 @@ class SystemInfo(models.Model): class Forum(models.Model): - system_info = models.ForeignKey(SystemInfo) + system_info = models.ForeignKey(SystemInfo, models.CASCADE) forum_name = models.CharField(max_length=32) @python_2_unicode_compatible class Post(models.Model): - forum = models.ForeignKey(Forum, null=True) + forum = models.ForeignKey(Forum, models.SET_NULL, null=True) title = models.CharField(max_length=32) def __str__(self): @@ -49,7 +49,7 @@ class Post(models.Model): @python_2_unicode_compatible class Comment(models.Model): - post = models.ForeignKey(Post, null=True) + post = models.ForeignKey(Post, models.SET_NULL, null=True) comment_text = models.CharField(max_length=250) class Meta: diff --git a/tests/null_queries/models.py b/tests/null_queries/models.py index 1c3808f407..8d915ba11f 100644 --- a/tests/null_queries/models.py +++ b/tests/null_queries/models.py @@ -14,7 +14,7 @@ class Poll(models.Model): @python_2_unicode_compatible class Choice(models.Model): - poll = models.ForeignKey(Poll) + poll = models.ForeignKey(Poll, models.CASCADE) choice = models.CharField(max_length=200) def __str__(self): @@ -32,6 +32,6 @@ class OuterB(models.Model): class Inner(models.Model): - first = models.ForeignKey(OuterA) + first = models.ForeignKey(OuterA, models.CASCADE) # second would clash with the __second lookup. - third = models.ForeignKey(OuterB, null=True) + third = models.ForeignKey(OuterB, models.SET_NULL, null=True) diff --git a/tests/one_to_one/models.py b/tests/one_to_one/models.py index 8a5defe856..788d81a592 100644 --- a/tests/one_to_one/models.py +++ b/tests/one_to_one/models.py @@ -22,7 +22,7 @@ class Place(models.Model): @python_2_unicode_compatible class Restaurant(models.Model): - place = models.OneToOneField(Place, primary_key=True) + place = models.OneToOneField(Place, models.CASCADE, primary_key=True) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) @@ -32,7 +32,7 @@ class Restaurant(models.Model): @python_2_unicode_compatible class Bar(models.Model): - place = models.OneToOneField(Place) + place = models.OneToOneField(Place, models.CASCADE) serves_cocktails = models.BooleanField(default=True) def __str__(self): @@ -40,13 +40,13 @@ class Bar(models.Model): class UndergroundBar(models.Model): - place = models.OneToOneField(Place, null=True) + place = models.OneToOneField(Place, models.SET_NULL, null=True) serves_cocktails = models.BooleanField(default=True) @python_2_unicode_compatible class Waiter(models.Model): - restaurant = models.ForeignKey(Restaurant) + restaurant = models.ForeignKey(Restaurant, models.CASCADE) name = models.CharField(max_length=50) def __str__(self): @@ -68,14 +68,14 @@ class ManualPrimaryKey(models.Model): class RelatedModel(models.Model): - link = models.OneToOneField(ManualPrimaryKey) + link = models.OneToOneField(ManualPrimaryKey, models.CASCADE) name = models.CharField(max_length=50) @python_2_unicode_compatible class MultiModel(models.Model): - link1 = models.OneToOneField(Place) - link2 = models.OneToOneField(ManualPrimaryKey) + link1 = models.OneToOneField(Place, models.CASCADE) + link2 = models.OneToOneField(ManualPrimaryKey, models.CASCADE) name = models.CharField(max_length=50) def __str__(self): @@ -87,15 +87,15 @@ class Target(models.Model): class Pointer(models.Model): - other = models.OneToOneField(Target, primary_key=True) + other = models.OneToOneField(Target, models.CASCADE, primary_key=True) class Pointer2(models.Model): - other = models.OneToOneField(Target, related_name='second_pointer') + other = models.OneToOneField(Target, models.CASCADE, related_name='second_pointer') class HiddenPointer(models.Model): - target = models.OneToOneField(Target, related_name='hidden+') + target = models.OneToOneField(Target, models.CASCADE, related_name='hidden+') # Test related objects visibility. @@ -116,5 +116,5 @@ class DirectorManager(models.Manager): class Director(models.Model): is_temp = models.BooleanField(default=False) - school = models.OneToOneField(School) + school = models.OneToOneField(School, models.CASCADE) objects = DirectorManager() diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py index 041fe6857c..807d504998 100644 --- a/tests/one_to_one/tests.py +++ b/tests/one_to_one/tests.py @@ -159,7 +159,7 @@ class OneToOneTests(TestCase): name = models.CharField(max_length=50) class BandManager(models.Model): - band = UnsavedOneToOneField(Band) + band = UnsavedOneToOneField(Band, models.CASCADE) first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) diff --git a/tests/order_with_respect_to/models.py b/tests/order_with_respect_to/models.py index 18dbd08dbc..7afc917b4b 100644 --- a/tests/order_with_respect_to/models.py +++ b/tests/order_with_respect_to/models.py @@ -14,7 +14,7 @@ class Question(models.Model): @python_2_unicode_compatible class Answer(models.Model): text = models.CharField(max_length=200) - question = models.ForeignKey(Question) + question = models.ForeignKey(Question, models.CASCADE) class Meta: order_with_respect_to = 'question' @@ -26,7 +26,7 @@ class Answer(models.Model): @python_2_unicode_compatible class Post(models.Model): title = models.CharField(max_length=200) - parent = models.ForeignKey("self", related_name="children", null=True) + parent = models.ForeignKey("self", models.SET_NULL, related_name="children", null=True) class Meta: order_with_respect_to = "parent" diff --git a/tests/order_with_respect_to/tests.py b/tests/order_with_respect_to/tests.py index 60181cca4b..ff92fdb6fb 100644 --- a/tests/order_with_respect_to/tests.py +++ b/tests/order_with_respect_to/tests.py @@ -91,7 +91,7 @@ class OrderWithRespectToTests2(TestCase): pass class Foo(models.Model): - bar = models.ForeignKey(Bar) + bar = models.ForeignKey(Bar, models.CASCADE) order = models.OrderWrt() class Meta: diff --git a/tests/ordering/models.py b/tests/ordering/models.py index c588a4e418..213a8f5ce8 100644 --- a/tests/ordering/models.py +++ b/tests/ordering/models.py @@ -24,8 +24,8 @@ class Author(models.Model): @python_2_unicode_compatible class Article(models.Model): - author = models.ForeignKey(Author, null=True) - second_author = models.ForeignKey(Author, null=True) + author = models.ForeignKey(Author, models.SET_NULL, null=True) + second_author = models.ForeignKey(Author, models.SET_NULL, null=True) headline = models.CharField(max_length=100) pub_date = models.DateTimeField() @@ -43,7 +43,7 @@ class OrderedByAuthorArticle(Article): class Reference(models.Model): - article = models.ForeignKey(OrderedByAuthorArticle) + article = models.ForeignKey(OrderedByAuthorArticle, models.CASCADE) class Meta: ordering = ('article',) diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py index c8fe842397..4be219f722 100644 --- a/tests/postgres_tests/migrations/0002_create_test_models.py +++ b/tests/postgres_tests/migrations/0002_create_test_models.py @@ -127,7 +127,11 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('int1', models.IntegerField()), ('int2', models.IntegerField()), - ('related_field', models.ForeignKey('postgres_tests.AggregateTestModel', null=True)), + ('related_field', models.ForeignKey( + 'postgres_tests.AggregateTestModel', + models.SET_NULL, + null=True, + )), ] ), migrations.CreateModel( @@ -158,7 +162,11 @@ class Migration(migrations.Migration): migrations.CreateModel( name='RangeLookupsModel', fields=[ - ('parent', models.ForeignKey('postgres_tests.RangesModel', blank=True, null=True)), + ('parent', models.ForeignKey( + 'postgres_tests.RangesModel', + models.SET_NULL, + blank=True, null=True, + )), ('integer', models.IntegerField(blank=True, null=True)), ('big_integer', models.BigIntegerField(blank=True, null=True)), ('float', models.FloatField(blank=True, null=True)), diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py index 4233092c79..22d43b2438 100644 --- a/tests/postgres_tests/models.py +++ b/tests/postgres_tests/models.py @@ -62,7 +62,7 @@ if connection.vendor == 'postgresql' and connection.pg_version >= 90200: dates = DateRangeField(blank=True, null=True) class RangeLookupsModel(PostgreSQLModel): - parent = models.ForeignKey(RangesModel, blank=True, null=True) + parent = models.ForeignKey(RangesModel, models.SET_NULL, blank=True, null=True) integer = models.IntegerField(blank=True, null=True) big_integer = models.BigIntegerField(blank=True, null=True) float = models.FloatField(blank=True, null=True) @@ -108,7 +108,7 @@ class StatTestModel(models.Model): """ int1 = models.IntegerField() int2 = models.IntegerField() - related_field = models.ForeignKey(AggregateTestModel, null=True) + related_field = models.ForeignKey(AggregateTestModel, models.SET_NULL, null=True) class NowTestModel(models.Model): diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py index 207f12a11a..32570e9109 100644 --- a/tests/prefetch_related/models.py +++ b/tests/prefetch_related/models.py @@ -13,7 +13,7 @@ from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class Author(models.Model): name = models.CharField(max_length=50, unique=True) - first_book = models.ForeignKey('Book', related_name='first_time_authors') + first_book = models.ForeignKey('Book', models.CASCADE, related_name='first_time_authors') favorite_authors = models.ManyToManyField( 'self', through='FavoriteAuthors', symmetrical=False, related_name='favors_me') @@ -25,13 +25,13 @@ class Author(models.Model): class AuthorWithAge(Author): - author = models.OneToOneField(Author, parent_link=True) + author = models.OneToOneField(Author, models.CASCADE, parent_link=True) age = models.IntegerField() class FavoriteAuthors(models.Model): - author = models.ForeignKey(Author, to_field='name', related_name='i_like') - likes_author = models.ForeignKey(Author, to_field='name', related_name='likes_me') + author = models.ForeignKey(Author, models.CASCADE, to_field='name', related_name='i_like') + likes_author = models.ForeignKey(Author, models.CASCADE, to_field='name', related_name='likes_me') class Meta: ordering = ['id'] @@ -39,7 +39,7 @@ class FavoriteAuthors(models.Model): @python_2_unicode_compatible class AuthorAddress(models.Model): - author = models.ForeignKey(Author, to_field='name', related_name='addresses') + author = models.ForeignKey(Author, models.CASCADE, to_field='name', related_name='addresses') address = models.TextField() class Meta: @@ -62,14 +62,14 @@ class Book(models.Model): class BookWithYear(Book): - book = models.OneToOneField(Book, parent_link=True) + book = models.OneToOneField(Book, models.CASCADE, parent_link=True) published_year = models.IntegerField() aged_authors = models.ManyToManyField( AuthorWithAge, related_name='books_with_year') class Bio(models.Model): - author = models.OneToOneField(Author) + author = models.OneToOneField(Author, models.CASCADE) books = models.ManyToManyField(Book, blank=True) @@ -86,7 +86,7 @@ class Reader(models.Model): class BookReview(models.Model): - book = models.ForeignKey(BookWithYear) + book = models.ForeignKey(BookWithYear, models.CASCADE) notes = models.TextField(null=True, blank=True) @@ -131,15 +131,27 @@ class Department(models.Model): @python_2_unicode_compatible class TaggedItem(models.Model): tag = models.SlugField() - content_type = models.ForeignKey(ContentType, related_name="taggeditem_set2") + content_type = models.ForeignKey( + ContentType, + models.CASCADE, + related_name="taggeditem_set2", + ) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') - created_by_ct = models.ForeignKey(ContentType, null=True, - related_name='taggeditem_set3') + created_by_ct = models.ForeignKey( + ContentType, + models.SET_NULL, + null=True, + related_name='taggeditem_set3', + ) created_by_fkey = models.PositiveIntegerField(null=True) created_by = GenericForeignKey('created_by_ct', 'created_by_fkey',) - favorite_ct = models.ForeignKey(ContentType, null=True, - related_name='taggeditem_set4') + favorite_ct = models.ForeignKey( + ContentType, + models.SET_NULL, + null=True, + related_name='taggeditem_set4', + ) favorite_fkey = models.CharField(max_length=64, null=True) favorite = GenericForeignKey('favorite_ct', 'favorite_fkey') @@ -166,7 +178,7 @@ class Comment(models.Model): comment = models.TextField() # Content-object field - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_pk = models.TextField() content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") @@ -179,8 +191,8 @@ class Comment(models.Model): class House(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=255) - owner = models.ForeignKey('Person', null=True) - main_room = models.OneToOneField('Room', related_name='main_room_of', null=True) + owner = models.ForeignKey('Person', models.SET_NULL, null=True) + main_room = models.OneToOneField('Room', models.SET_NULL, related_name='main_room_of', null=True) class Meta: ordering = ['id'] @@ -188,7 +200,7 @@ class House(models.Model): class Room(models.Model): name = models.CharField(max_length=50) - house = models.ForeignKey(House, related_name='rooms') + house = models.ForeignKey(House, models.CASCADE, related_name='rooms') class Meta: ordering = ['id'] @@ -216,8 +228,7 @@ class Person(models.Model): @python_2_unicode_compatible class Employee(models.Model): name = models.CharField(max_length=50) - boss = models.ForeignKey('self', null=True, - related_name='serfs') + boss = models.ForeignKey('self', models.SET_NULL, null=True, related_name='serfs') def __str__(self): return self.name @@ -239,7 +250,7 @@ class LessonEntry(models.Model): @python_2_unicode_compatible class WordEntry(models.Model): - lesson_entry = models.ForeignKey(LessonEntry) + lesson_entry = models.ForeignKey(LessonEntry, models.CASCADE) name = models.CharField(max_length=200) def __str__(self): @@ -251,7 +262,7 @@ class WordEntry(models.Model): @python_2_unicode_compatible class Author2(models.Model): name = models.CharField(max_length=50, unique=True) - first_book = models.ForeignKey('Book', related_name='first_time_authors+') + first_book = models.ForeignKey('Book', models.CASCADE, related_name='first_time_authors+') favorite_books = models.ManyToManyField('Book', related_name='+') def __str__(self): @@ -271,6 +282,6 @@ class Pet(models.Model): class Flea(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - current_room = models.ForeignKey(Room, related_name='fleas', null=True) + current_room = models.ForeignKey(Room, models.SET_NULL, related_name='fleas', null=True) pets_visited = models.ManyToManyField(Pet, related_name='fleas_hosted') people_visited = models.ManyToManyField(Person, related_name='fleas_hosted') diff --git a/tests/proxy_models/models.py b/tests/proxy_models/models.py index 463fd2cd5b..145f70dac6 100644 --- a/tests/proxy_models/models.py +++ b/tests/proxy_models/models.py @@ -124,7 +124,7 @@ class Country(models.Model): @python_2_unicode_compatible class State(models.Model): name = models.CharField(max_length=50) - country = models.ForeignKey(Country) + country = models.ForeignKey(Country, models.CASCADE) def __str__(self): return self.name @@ -158,7 +158,7 @@ class ProxyTrackerUser(TrackerUser): @python_2_unicode_compatible class Issue(models.Model): summary = models.CharField(max_length=255) - assignee = models.ForeignKey(ProxyTrackerUser) + assignee = models.ForeignKey(ProxyTrackerUser, models.CASCADE) def __str__(self): return ':'.join((self.__class__.__name__, self.summary,)) @@ -166,7 +166,7 @@ class Issue(models.Model): class Bug(Issue): version = models.CharField(max_length=50) - reporter = models.ForeignKey(BaseUser) + reporter = models.ForeignKey(BaseUser, models.CASCADE) class ProxyBug(Bug): @@ -191,8 +191,8 @@ class Improvement(Issue): or to a proxy of proxy model """ version = models.CharField(max_length=50) - reporter = models.ForeignKey(ProxyTrackerUser) - associated_bug = models.ForeignKey(ProxyProxyBug) + reporter = models.ForeignKey(ProxyTrackerUser, models.CASCADE) + associated_bug = models.ForeignKey(ProxyProxyBug, models.CASCADE) class ProxyImprovement(Improvement): diff --git a/tests/queries/models.py b/tests/queries/models.py index 26d3cf4627..47c96de612 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -30,9 +30,13 @@ class NamedCategory(DumbCategory): @python_2_unicode_compatible class Tag(models.Model): name = models.CharField(max_length=10) - parent = models.ForeignKey('self', blank=True, null=True, - related_name='children') - category = models.ForeignKey(NamedCategory, null=True, default=None) + parent = models.ForeignKey( + 'self', + models.SET_NULL, + blank=True, null=True, + related_name='children', + ) + category = models.ForeignKey(NamedCategory, models.SET_NULL, null=True, default=None) class Meta: ordering = ['name'] @@ -63,7 +67,7 @@ class Note(models.Model): @python_2_unicode_compatible class Annotation(models.Model): name = models.CharField(max_length=10) - tag = models.ForeignKey(Tag) + tag = models.ForeignKey(Tag, models.CASCADE) notes = models.ManyToManyField(Note) def __str__(self): @@ -73,7 +77,7 @@ class Annotation(models.Model): @python_2_unicode_compatible class ExtraInfo(models.Model): info = models.CharField(max_length=100) - note = models.ForeignKey(Note) + note = models.ForeignKey(Note, models.CASCADE) value = models.IntegerField(null=True) class Meta: @@ -87,7 +91,7 @@ class ExtraInfo(models.Model): class Author(models.Model): name = models.CharField(max_length=10) num = models.IntegerField(unique=True) - extra = models.ForeignKey(ExtraInfo) + extra = models.ForeignKey(ExtraInfo, models.CASCADE) class Meta: ordering = ['name'] @@ -102,8 +106,8 @@ class Item(models.Model): created = models.DateTimeField() modified = models.DateTimeField(blank=True, null=True) tags = models.ManyToManyField(Tag, blank=True) - creator = models.ForeignKey(Author) - note = models.ForeignKey(Note) + creator = models.ForeignKey(Author, models.CASCADE) + note = models.ForeignKey(Note, models.CASCADE) class Meta: ordering = ['-note', 'name'] @@ -115,7 +119,7 @@ class Item(models.Model): @python_2_unicode_compatible class Report(models.Model): name = models.CharField(max_length=10) - creator = models.ForeignKey(Author, to_field='num', null=True) + creator = models.ForeignKey(Author, models.SET_NULL, to_field='num', null=True) def __str__(self): return self.name @@ -124,7 +128,7 @@ class Report(models.Model): @python_2_unicode_compatible class Ranking(models.Model): rank = models.IntegerField() - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) class Meta: # A complex ordering specification. Should stress the system a bit. @@ -137,7 +141,7 @@ class Ranking(models.Model): @python_2_unicode_compatible class Cover(models.Model): title = models.CharField(max_length=50) - item = models.ForeignKey(Item) + item = models.ForeignKey(Item, models.CASCADE) class Meta: ordering = ['item'] @@ -169,32 +173,32 @@ class Valid(models.Model): class X(models.Model): - y = models.ForeignKey('Y') + y = models.ForeignKey('Y', models.CASCADE) class Y(models.Model): - x1 = models.ForeignKey(X, related_name='y1') + x1 = models.ForeignKey(X, models.CASCADE, related_name='y1') # Some models with a cycle in the default ordering. This would be bad if we # didn't catch the infinite loop. class LoopX(models.Model): - y = models.ForeignKey('LoopY') + y = models.ForeignKey('LoopY', models.CASCADE) class Meta: ordering = ['y'] class LoopY(models.Model): - x = models.ForeignKey(LoopX) + x = models.ForeignKey(LoopX, models.CASCADE) class Meta: ordering = ['x'] class LoopZ(models.Model): - z = models.ForeignKey('self') + z = models.ForeignKey('self', models.CASCADE) class Meta: ordering = ['z'] @@ -212,7 +216,7 @@ class CustomManager(models.Manager): @python_2_unicode_compatible class ManagedModel(models.Model): data = models.CharField(max_length=10) - tag = models.ForeignKey(Tag) + tag = models.ForeignKey(Tag, models.CASCADE) public = models.BooleanField(default=True) objects = CustomManager() @@ -235,14 +239,14 @@ class MemberManager(models.Manager): class Member(models.Model): name = models.CharField(max_length=10) - details = models.OneToOneField(Detail, primary_key=True) + details = models.OneToOneField(Detail, models.CASCADE, primary_key=True) objects = MemberManager() class Child(models.Model): - person = models.OneToOneField(Member, primary_key=True) - parent = models.ForeignKey(Member, related_name="children") + person = models.OneToOneField(Member, models.CASCADE, primary_key=True) + parent = models.ForeignKey(Member, models.CASCADE, related_name="children") # Custom primary keys interfered with ordering in the past. @@ -256,7 +260,7 @@ class CustomPk(models.Model): class Related(models.Model): - custom = models.ForeignKey(CustomPk) + custom = models.ForeignKey(CustomPk, models.CASCADE) class CustomPkTag(models.Model): @@ -271,7 +275,7 @@ class CustomPkTag(models.Model): @python_2_unicode_compatible class Celebrity(models.Model): name = models.CharField("Name", max_length=20) - greatest_fan = models.ForeignKey("Fan", null=True, unique=True) + greatest_fan = models.ForeignKey("Fan", models.SET_NULL, null=True, unique=True) def __str__(self): return self.name @@ -282,7 +286,7 @@ class TvChef(Celebrity): class Fan(models.Model): - fan_of = models.ForeignKey(Celebrity) + fan_of = models.ForeignKey(Celebrity, models.CASCADE) # Multiple foreign keys @@ -300,8 +304,8 @@ class LeafB(models.Model): class Join(models.Model): - a = models.ForeignKey(LeafA) - b = models.ForeignKey(LeafB) + a = models.ForeignKey(LeafA, models.CASCADE) + b = models.ForeignKey(LeafB, models.CASCADE) @python_2_unicode_compatible @@ -324,11 +328,11 @@ class SharedConnection(models.Model): class PointerA(models.Model): - connection = models.ForeignKey(SharedConnection) + connection = models.ForeignKey(SharedConnection, models.CASCADE) class PointerB(models.Model): - connection = models.ForeignKey(SharedConnection) + connection = models.ForeignKey(SharedConnection, models.CASCADE) # Multi-layer ordering @@ -345,7 +349,7 @@ class SingleObject(models.Model): class RelatedObject(models.Model): - single = models.ForeignKey(SingleObject, null=True) + single = models.ForeignKey(SingleObject, models.SET_NULL, null=True) f = models.IntegerField(null=True) class Meta: @@ -355,7 +359,7 @@ class RelatedObject(models.Model): @python_2_unicode_compatible class Plaything(models.Model): name = models.CharField(max_length=10) - others = models.ForeignKey(RelatedObject, null=True) + others = models.ForeignKey(RelatedObject, models.SET_NULL, null=True) class Meta: ordering = ['others'] @@ -383,7 +387,7 @@ class Food(models.Model): @python_2_unicode_compatible class Eaten(models.Model): - food = models.ForeignKey(Food, to_field="name", null=True) + food = models.ForeignKey(Food, models.SET_NULL, to_field="name", null=True) meal = models.CharField(max_length=20) def __str__(self): @@ -393,7 +397,7 @@ class Eaten(models.Model): @python_2_unicode_compatible class Node(models.Model): num = models.IntegerField(unique=True) - parent = models.ForeignKey("self", to_field="num", null=True) + parent = models.ForeignKey("self", models.SET_NULL, to_field="num", null=True) def __str__(self): return "%s" % self.num @@ -425,7 +429,7 @@ class ChildObjectA(ObjectA): @python_2_unicode_compatible class ObjectB(models.Model): name = models.CharField(max_length=50) - objecta = models.ForeignKey(ObjectA) + objecta = models.ForeignKey(ObjectA, models.CASCADE) num = models.PositiveSmallIntegerField() def __str__(self): @@ -440,9 +444,9 @@ class ProxyObjectB(ObjectB): @python_2_unicode_compatible class ObjectC(models.Model): name = models.CharField(max_length=50) - objecta = models.ForeignKey(ObjectA, null=True) - objectb = models.ForeignKey(ObjectB, null=True) - childobjecta = models.ForeignKey(ChildObjectA, null=True, related_name='ca_pk') + objecta = models.ForeignKey(ObjectA, models.SET_NULL, null=True) + objectb = models.ForeignKey(ObjectB, models.SET_NULL, null=True) + childobjecta = models.ForeignKey(ChildObjectA, models.SET_NULL, null=True, related_name='ca_pk') def __str__(self): return self.name @@ -466,7 +470,7 @@ class SpecialCategory(SimpleCategory): @python_2_unicode_compatible class CategoryItem(models.Model): - category = models.ForeignKey(SimpleCategory) + category = models.ForeignKey(SimpleCategory, models.CASCADE) def __str__(self): return "category item: " + str(self.category) @@ -475,15 +479,15 @@ class CategoryItem(models.Model): @python_2_unicode_compatible class OneToOneCategory(models.Model): new_name = models.CharField(max_length=15) - category = models.OneToOneField(SimpleCategory) + category = models.OneToOneField(SimpleCategory, models.CASCADE) def __str__(self): return "one2one " + self.new_name class CategoryRelationship(models.Model): - first = models.ForeignKey(SimpleCategory, related_name='first_rel') - second = models.ForeignKey(SimpleCategory, related_name='second_rel') + first = models.ForeignKey(SimpleCategory, models.CASCADE, related_name='first_rel') + second = models.ForeignKey(SimpleCategory, models.CASCADE, related_name='second_rel') class NullableName(models.Model): @@ -503,13 +507,13 @@ class ModelC(models.Model): class ModelB(models.Model): name = models.TextField() - c = models.ForeignKey(ModelC) + c = models.ForeignKey(ModelC, models.CASCADE) class ModelA(models.Model): name = models.TextField() - b = models.ForeignKey(ModelB, null=True) - d = models.ForeignKey(ModelD) + b = models.ForeignKey(ModelB, models.SET_NULL, null=True) + d = models.ForeignKey(ModelD, models.CASCADE) @python_2_unicode_compatible @@ -521,8 +525,8 @@ class Job(models.Model): class JobResponsibilities(models.Model): - job = models.ForeignKey(Job, to_field='name') - responsibility = models.ForeignKey('Responsibility', to_field='description') + job = models.ForeignKey(Job, models.SET_NULL, to_field='name') + responsibility = models.ForeignKey('Responsibility', models.SET_NULL, to_field='description') @python_2_unicode_compatible @@ -553,9 +557,9 @@ class FK3(models.Model): class BaseA(models.Model): - a = models.ForeignKey(FK1, null=True) - b = models.ForeignKey(FK2, null=True) - c = models.ForeignKey(FK3, null=True) + a = models.ForeignKey(FK1, models.SET_NULL, null=True) + b = models.ForeignKey(FK2, models.SET_NULL, null=True) + c = models.ForeignKey(FK3, models.SET_NULL, null=True) @python_2_unicode_compatible @@ -567,22 +571,22 @@ class Identifier(models.Model): class Program(models.Model): - identifier = models.OneToOneField(Identifier) + identifier = models.OneToOneField(Identifier, models.CASCADE) class Channel(models.Model): programs = models.ManyToManyField(Program) - identifier = models.OneToOneField(Identifier) + identifier = models.OneToOneField(Identifier, models.CASCADE) class Book(models.Model): title = models.TextField() - chapter = models.ForeignKey('Chapter') + chapter = models.ForeignKey('Chapter', models.CASCADE) class Chapter(models.Model): title = models.TextField() - paragraph = models.ForeignKey('Paragraph') + paragraph = models.ForeignKey('Paragraph', models.CASCADE) class Paragraph(models.Model): @@ -595,7 +599,7 @@ class Page(models.Model): class MyObject(models.Model): - parent = models.ForeignKey('self', null=True, blank=True, related_name='children') + parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True, related_name='children') data = models.CharField(max_length=100) created_at = models.DateTimeField(auto_now_add=True) @@ -615,7 +619,7 @@ class Order(models.Model): @python_2_unicode_compatible class OrderItem(models.Model): - order = models.ForeignKey(Order, related_name='items') + order = models.ForeignKey(Order, models.SET_NULL, related_name='items') status = models.IntegerField() class Meta: @@ -632,8 +636,8 @@ class BaseUser(models.Model): @python_2_unicode_compatible class Task(models.Model): title = models.CharField(max_length=10) - owner = models.ForeignKey(BaseUser, related_name='owner') - creator = models.ForeignKey(BaseUser, related_name='creator') + owner = models.ForeignKey(BaseUser, models.SET_NULL, related_name='owner') + creator = models.ForeignKey(BaseUser, models.SET_NULL, related_name='creator') def __str__(self): return self.title @@ -649,7 +653,7 @@ class Staff(models.Model): @python_2_unicode_compatible class StaffUser(BaseUser): - staff = models.OneToOneField(Staff, related_name='user') + staff = models.OneToOneField(Staff, models.SET_NULL, related_name='user') def __str__(self): return self.staff @@ -663,7 +667,7 @@ class Ticket21203Parent(models.Model): class Ticket21203Child(models.Model): childid = models.AutoField(primary_key=True) - parent = models.ForeignKey(Ticket21203Parent) + parent = models.ForeignKey(Ticket21203Parent, models.CASCADE) class Person(models.Model): @@ -680,8 +684,8 @@ class Company(models.Model): class Employment(models.Model): - employer = models.ForeignKey(Company) - employee = models.ForeignKey(Person) + employer = models.ForeignKey(Company, models.CASCADE) + employee = models.ForeignKey(Person, models.CASCADE) title = models.CharField(max_length=128) @@ -692,11 +696,11 @@ class School(models.Model): class Student(models.Model): - school = models.ForeignKey(School) + school = models.ForeignKey(School, models.CASCADE) class Classroom(models.Model): - school = models.ForeignKey(School) + school = models.ForeignKey(School, models.CASCADE) students = models.ManyToManyField(Student, related_name='classroom') @@ -709,8 +713,8 @@ class Ticket23605A(Ticket23605AParent): class Ticket23605B(models.Model): - modela_fk = models.ForeignKey(Ticket23605A) - modelc_fk = models.ForeignKey("Ticket23605C") + modela_fk = models.ForeignKey(Ticket23605A, models.CASCADE) + modelc_fk = models.ForeignKey("Ticket23605C", models.CASCADE) field_b0 = models.IntegerField(null=True) field_b1 = models.BooleanField(default=False) @@ -728,7 +732,7 @@ class Individual(models.Model): class RelatedIndividual(models.Model): - related = models.ForeignKey(Individual, related_name='related_individual') + related = models.ForeignKey(Individual, models.CASCADE, related_name='related_individual') class Meta: db_table = 'RelatedIndividual' diff --git a/tests/queryset_pickle/models.py b/tests/queryset_pickle/models.py index bb20e71524..5e60963272 100644 --- a/tests/queryset_pickle/models.py +++ b/tests/queryset_pickle/models.py @@ -38,7 +38,7 @@ class Group(models.Model): class Event(models.Model): title = models.CharField(max_length=100) - group = models.ForeignKey(Group) + group = models.ForeignKey(Group, models.CASCADE) class Happening(models.Model): diff --git a/tests/raw_query/models.py b/tests/raw_query/models.py index 2a888088ef..fd122d4dbe 100644 --- a/tests/raw_query/models.py +++ b/tests/raw_query/models.py @@ -18,13 +18,13 @@ class Author(models.Model): class Book(models.Model): title = models.CharField(max_length=255) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) paperback = models.BooleanField(default=False) opening_line = models.TextField() class BookFkAsPk(models.Model): - book = models.ForeignKey(Book, primary_key=True, db_column="not_the_default") + book = models.ForeignKey(Book, models.CASCADE, primary_key=True, db_column="not_the_default") class Coffee(models.Model): diff --git a/tests/reverse_lookup/models.py b/tests/reverse_lookup/models.py index 4f328dd063..51e879bf68 100644 --- a/tests/reverse_lookup/models.py +++ b/tests/reverse_lookup/models.py @@ -19,7 +19,7 @@ class User(models.Model): @python_2_unicode_compatible class Poll(models.Model): question = models.CharField(max_length=200) - creator = models.ForeignKey(User) + creator = models.ForeignKey(User, models.CASCADE) def __str__(self): return self.question @@ -28,8 +28,8 @@ class Poll(models.Model): @python_2_unicode_compatible class Choice(models.Model): name = models.CharField(max_length=100) - poll = models.ForeignKey(Poll, related_name="poll_choice") - related_poll = models.ForeignKey(Poll, related_name="related_choice") + poll = models.ForeignKey(Poll, models.CASCADE, related_name="poll_choice") + related_poll = models.ForeignKey(Poll, models.CASCADE, related_name="related_choice") def __str__(self): return self.name diff --git a/tests/schema/models.py b/tests/schema/models.py index 7a5454761e..adfa505420 100644 --- a/tests/schema/models.py +++ b/tests/schema/models.py @@ -34,7 +34,7 @@ class AuthorWithEvenLongerName(models.Model): class Book(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=100, db_index=True) pub_date = models.DateTimeField() # tags = models.ManyToManyField("Tag", related_name="books") @@ -44,7 +44,7 @@ class Book(models.Model): class BookWeak(models.Model): - author = models.ForeignKey(Author, db_constraint=False) + author = models.ForeignKey(Author, models.CASCADE, db_constraint=False) title = models.CharField(max_length=100, db_index=True) pub_date = models.DateTimeField() @@ -53,14 +53,17 @@ class BookWeak(models.Model): class BookWithLongName(models.Model): - author_foreign_key_with_really_long_field_name = models.ForeignKey(AuthorWithEvenLongerName) + author_foreign_key_with_really_long_field_name = models.ForeignKey( + AuthorWithEvenLongerName, + models.CASCADE, + ) class Meta: apps = new_apps class BookWithO2O(models.Model): - author = models.OneToOneField(Author) + author = models.OneToOneField(Author, models.CASCADE) title = models.CharField(max_length=100, db_index=True) pub_date = models.DateTimeField() @@ -70,7 +73,7 @@ class BookWithO2O(models.Model): class BookWithSlug(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=100, db_index=True) pub_date = models.DateTimeField() slug = models.CharField(max_length=20, unique=True) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 567ee768a5..1852b70757 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -7,6 +7,7 @@ from django.db import ( DatabaseError, IntegrityError, OperationalError, connection, ) from django.db.models import Model +from django.db.models.deletion import CASCADE from django.db.models.fields import ( AutoField, BigIntegerField, BinaryField, BooleanField, CharField, DateField, DateTimeField, IntegerField, PositiveIntegerField, SlugField, @@ -161,7 +162,7 @@ class SchemaTests(TransactionTestCase): ) # Repoint the FK constraint old_field = Book._meta.get_field("author") - new_field = ForeignKey(Tag) + new_field = ForeignKey(Tag, CASCADE) new_field.set_attributes_from_name("author") with connection.schema_editor() as editor: editor.alter_field(Book, old_field, new_field, strict=True) @@ -192,7 +193,7 @@ class SchemaTests(TransactionTestCase): if details['columns'] == ["author_id"] and details['foreign_key']: self.fail("FK constraint for author_id found") # Make a db_constraint=False FK - new_field = ForeignKey(Tag, db_constraint=False) + new_field = ForeignKey(Tag, CASCADE, db_constraint=False) new_field.set_attributes_from_name("tag") with connection.schema_editor() as editor: editor.add_field(Author, new_field) @@ -202,7 +203,7 @@ class SchemaTests(TransactionTestCase): if details['columns'] == ["tag_id"] and details['foreign_key']: self.fail("FK constraint for tag_id found") # Alter to one with a constraint - new_field2 = ForeignKey(Tag) + new_field2 = ForeignKey(Tag, CASCADE) new_field2.set_attributes_from_name("tag") with connection.schema_editor() as editor: editor.alter_field(Author, new_field, new_field2, strict=True) @@ -215,7 +216,7 @@ class SchemaTests(TransactionTestCase): else: self.fail("No FK constraint for tag_id found") # Alter to one without a constraint again - new_field2 = ForeignKey(Tag) + new_field2 = ForeignKey(Tag, CASCADE) new_field2.set_attributes_from_name("tag") with connection.schema_editor() as editor: editor.alter_field(Author, new_field2, new_field, strict=True) @@ -632,7 +633,7 @@ class SchemaTests(TransactionTestCase): self.fail("No FK constraint for author_id found") # Alter the FK old_field = Book._meta.get_field("author") - new_field = ForeignKey(Author, editable=False) + new_field = ForeignKey(Author, CASCADE, editable=False) new_field.set_attributes_from_name("author") with connection.schema_editor() as editor: editor.alter_field(Book, old_field, new_field, strict=True) @@ -674,7 +675,7 @@ class SchemaTests(TransactionTestCase): if details['foreign_key']: self.fail('Found an unexpected FK constraint to %s' % details['columns']) old_field = LocalBook._meta.get_field("author") - new_field = ForeignKey(Author) + new_field = ForeignKey(Author, CASCADE) new_field.set_attributes_from_name("author") with connection.schema_editor() as editor: editor.alter_field(LocalBook, old_field, new_field, strict=True) @@ -715,7 +716,7 @@ class SchemaTests(TransactionTestCase): self.assertTrue(author_is_fk, "No FK constraint for author_id found") # Alter the OneToOneField to ForeignKey old_field = BookWithO2O._meta.get_field("author") - new_field = ForeignKey(Author) + new_field = ForeignKey(Author, CASCADE) new_field.set_attributes_from_name("author") with connection.schema_editor() as editor: editor.alter_field(BookWithO2O, old_field, new_field, strict=True) @@ -761,7 +762,7 @@ class SchemaTests(TransactionTestCase): self.assertTrue(author_is_fk, "No FK constraint for author_id found") # Alter the ForeignKey to OneToOneField old_field = Book._meta.get_field("author") - new_field = OneToOneField(Author) + new_field = OneToOneField(Author, CASCADE) new_field.set_attributes_from_name("author") with connection.schema_editor() as editor: editor.alter_field(Book, old_field, new_field, strict=True) @@ -901,7 +902,7 @@ class SchemaTests(TransactionTestCase): Tests M2M fields on models during creation """ class LocalBookWithM2M(Model): - author = ForeignKey(Author) + author = ForeignKey(Author, CASCADE) title = CharField(max_length=100, db_index=True) pub_date = DateTimeField() tags = M2MFieldClass("TagM2MTest", related_name="books") @@ -937,8 +938,8 @@ class SchemaTests(TransactionTestCase): Tests M2M fields on models during creation with through models """ class LocalTagThrough(Model): - book = ForeignKey("schema.LocalBookWithM2MThrough") - tag = ForeignKey("schema.TagM2MTest") + book = ForeignKey("schema.LocalBookWithM2MThrough", CASCADE) + tag = ForeignKey("schema.TagM2MTest", CASCADE) class Meta: app_label = 'schema' @@ -1026,8 +1027,8 @@ class SchemaTests(TransactionTestCase): Tests altering M2Ms with explicit through models (should no-op) """ class LocalAuthorTag(Model): - author = ForeignKey("schema.LocalAuthorWithM2MThrough") - tag = ForeignKey("schema.TagM2MTest") + author = ForeignKey("schema.LocalAuthorWithM2MThrough", CASCADE) + tag = ForeignKey("schema.TagM2MTest", CASCADE) class Meta: app_label = 'schema' @@ -1073,7 +1074,7 @@ class SchemaTests(TransactionTestCase): Tests repointing M2M fields """ class LocalBookWithM2M(Model): - author = ForeignKey(Author) + author = ForeignKey(Author, CASCADE) title = CharField(max_length=100, db_index=True) pub_date = DateTimeField() tags = M2MFieldClass("TagM2MTest", related_name="books") @@ -1264,7 +1265,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.create_model(Author) editor.create_model(BookWithoutAuthor) - new_field = ForeignKey(Author) + new_field = ForeignKey(Author, CASCADE) new_field.set_attributes_from_name('author') editor.add_field(BookWithoutAuthor, new_field) # Ensure the fields aren't unique to begin with @@ -1502,7 +1503,7 @@ class SchemaTests(TransactionTestCase): editor.create_model(AuthorWithEvenLongerName) editor.create_model(BookWithLongName) # Add a second FK, this would fail due to long ref name before the fix - new_field = ForeignKey(AuthorWithEvenLongerName, related_name="something") + new_field = ForeignKey(AuthorWithEvenLongerName, CASCADE, related_name="something") new_field.set_attributes_from_name("author_other_really_long_named_i_mean_so_long_fk") with connection.schema_editor() as editor: editor.add_field(BookWithLongName, new_field) @@ -1511,7 +1512,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.create_model(BookForeignObj) - new_field = ForeignObject(Author, from_fields=['author_id'], to_fields=['id']) + new_field = ForeignObject(Author, on_delete=CASCADE, from_fields=['author_id'], to_fields=['id']) new_field.set_attributes_from_name('author') with connection.schema_editor() as editor: editor.add_field(BookForeignObj, new_field) @@ -1587,7 +1588,7 @@ class SchemaTests(TransactionTestCase): "to_column": editor.quote_name(model._meta.auto_field.column), } ) - editor.alter_field(model, get_field(Author, field_class=ForeignKey), field) + editor.alter_field(model, get_field(Author, CASCADE, field_class=ForeignKey), field) def test_add_field_use_effective_default(self): """ diff --git a/tests/select_related/models.py b/tests/select_related/models.py index 04aeaa1b61..bef2873731 100644 --- a/tests/select_related/models.py +++ b/tests/select_related/models.py @@ -29,7 +29,7 @@ class Domain(models.Model): @python_2_unicode_compatible class Kingdom(models.Model): name = models.CharField(max_length=50) - domain = models.ForeignKey(Domain) + domain = models.ForeignKey(Domain, models.CASCADE) def __str__(self): return self.name @@ -38,7 +38,7 @@ class Kingdom(models.Model): @python_2_unicode_compatible class Phylum(models.Model): name = models.CharField(max_length=50) - kingdom = models.ForeignKey(Kingdom) + kingdom = models.ForeignKey(Kingdom, models.CASCADE) def __str__(self): return self.name @@ -47,7 +47,7 @@ class Phylum(models.Model): @python_2_unicode_compatible class Klass(models.Model): name = models.CharField(max_length=50) - phylum = models.ForeignKey(Phylum) + phylum = models.ForeignKey(Phylum, models.CASCADE) def __str__(self): return self.name @@ -56,7 +56,7 @@ class Klass(models.Model): @python_2_unicode_compatible class Order(models.Model): name = models.CharField(max_length=50) - klass = models.ForeignKey(Klass) + klass = models.ForeignKey(Klass, models.CASCADE) def __str__(self): return self.name @@ -65,7 +65,7 @@ class Order(models.Model): @python_2_unicode_compatible class Family(models.Model): name = models.CharField(max_length=50) - order = models.ForeignKey(Order) + order = models.ForeignKey(Order, models.CASCADE) def __str__(self): return self.name @@ -74,7 +74,7 @@ class Family(models.Model): @python_2_unicode_compatible class Genus(models.Model): name = models.CharField(max_length=50) - family = models.ForeignKey(Family) + family = models.ForeignKey(Family, models.CASCADE) def __str__(self): return self.name @@ -83,7 +83,7 @@ class Genus(models.Model): @python_2_unicode_compatible class Species(models.Model): name = models.CharField(max_length=50) - genus = models.ForeignKey(Genus) + genus = models.ForeignKey(Genus, models.CASCADE) def __str__(self): return self.name @@ -94,8 +94,8 @@ class Species(models.Model): @python_2_unicode_compatible class HybridSpecies(models.Model): name = models.CharField(max_length=50) - parent_1 = models.ForeignKey(Species, related_name='child_1') - parent_2 = models.ForeignKey(Species, related_name='child_2') + parent_1 = models.ForeignKey(Species, models.CASCADE, related_name='child_1') + parent_2 = models.ForeignKey(Species, models.CASCADE, related_name='child_2') def __str__(self): return self.name @@ -122,7 +122,7 @@ class Pizza(models.Model): class TaggedItem(models.Model): tag = models.CharField(max_length=30) - content_type = models.ForeignKey(ContentType, related_name='select_related_tagged_items') + content_type = models.ForeignKey(ContentType, models.CASCADE, related_name='select_related_tagged_items') object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') diff --git a/tests/select_related_onetoone/models.py b/tests/select_related_onetoone/models.py index 9af1b3f31b..cb9221ea1c 100644 --- a/tests/select_related_onetoone/models.py +++ b/tests/select_related_onetoone/models.py @@ -13,7 +13,7 @@ class User(models.Model): @python_2_unicode_compatible class UserProfile(models.Model): - user = models.OneToOneField(User) + user = models.OneToOneField(User, models.CASCADE) city = models.CharField(max_length=100) state = models.CharField(max_length=2) @@ -31,9 +31,9 @@ class UserStatResult(models.Model): @python_2_unicode_compatible class UserStat(models.Model): - user = models.OneToOneField(User, primary_key=True) + user = models.OneToOneField(User, models.CASCADE, primary_key=True) posts = models.IntegerField() - results = models.ForeignKey(UserStatResult) + results = models.ForeignKey(UserStatResult, models.CASCADE) def __str__(self): return 'UserStat, posts = %s' % (self.posts,) @@ -41,7 +41,7 @@ class UserStat(models.Model): @python_2_unicode_compatible class StatDetails(models.Model): - base_stats = models.OneToOneField(UserStat) + base_stats = models.OneToOneField(UserStat, models.CASCADE) comments = models.IntegerField() def __str__(self): @@ -58,7 +58,7 @@ class Image(models.Model): class Product(models.Model): name = models.CharField(max_length=100) - image = models.OneToOneField(Image, null=True) + image = models.OneToOneField(Image, models.SET_NULL, null=True) @python_2_unicode_compatible @@ -89,7 +89,7 @@ class Child1(Parent1, Parent2): @python_2_unicode_compatible class Child2(Parent1): - parent2 = models.OneToOneField(Parent2) + parent2 = models.OneToOneField(Parent2, models.CASCADE) value = models.IntegerField() def __str__(self): diff --git a/tests/select_related_regress/models.py b/tests/select_related_regress/models.py index c2611b4843..8e748d3eef 100644 --- a/tests/select_related_regress/models.py +++ b/tests/select_related_regress/models.py @@ -14,7 +14,7 @@ class Building(models.Model): @python_2_unicode_compatible class Device(models.Model): - building = models.ForeignKey('Building') + building = models.ForeignKey('Building', models.CASCADE) name = models.CharField(max_length=10) def __str__(self): @@ -23,7 +23,7 @@ class Device(models.Model): @python_2_unicode_compatible class Port(models.Model): - device = models.ForeignKey('Device') + device = models.ForeignKey('Device', models.CASCADE) port_number = models.CharField(max_length=10) def __str__(self): @@ -32,9 +32,18 @@ class Port(models.Model): @python_2_unicode_compatible class Connection(models.Model): - start = models.ForeignKey(Port, related_name='connection_start', - unique=True) - end = models.ForeignKey(Port, related_name='connection_end', unique=True) + start = models.ForeignKey( + Port, + models.CASCADE, + related_name='connection_start', + unique=True, + ) + end = models.ForeignKey( + Port, + models.CASCADE, + related_name='connection_end', + unique=True, + ) def __str__(self): return "%s to %s" % (self.start, self.end) @@ -48,24 +57,24 @@ class TUser(models.Model): class Person(models.Model): - user = models.ForeignKey(TUser, unique=True) + user = models.ForeignKey(TUser, models.CASCADE, unique=True) class Organizer(models.Model): - person = models.ForeignKey(Person) + person = models.ForeignKey(Person, models.CASCADE) class Student(models.Model): - person = models.ForeignKey(Person) + person = models.ForeignKey(Person, models.CASCADE) class Class(models.Model): - org = models.ForeignKey(Organizer) + org = models.ForeignKey(Organizer, models.CASCADE) class Enrollment(models.Model): - std = models.ForeignKey(Student) - cls = models.ForeignKey(Class) + std = models.ForeignKey(Student, models.CASCADE) + cls = models.ForeignKey(Class, models.CASCADE) # Models for testing bug #8036. @@ -76,7 +85,7 @@ class Country(models.Model): class State(models.Model): name = models.CharField(max_length=50) - country = models.ForeignKey(Country) + country = models.ForeignKey(Country, models.CASCADE) class ClientStatus(models.Model): @@ -85,8 +94,8 @@ class ClientStatus(models.Model): class Client(models.Model): name = models.CharField(max_length=50) - state = models.ForeignKey(State, null=True) - status = models.ForeignKey(ClientStatus) + state = models.ForeignKey(State, models.SET_NULL, null=True) + status = models.ForeignKey(ClientStatus, models.CASCADE) class SpecialClient(Client): @@ -110,7 +119,7 @@ class Child(Parent): @python_2_unicode_compatible class Item(models.Model): name = models.CharField(max_length=10) - child = models.ForeignKey(Child, null=True) + child = models.ForeignKey(Child, models.SET_NULL, null=True) def __str__(self): return self.name @@ -131,7 +140,7 @@ class Hen(Fowl): class Chick(Fowl): - mother = models.ForeignKey(Hen) + mother = models.ForeignKey(Hen, models.CASCADE) class Base(models.Model): @@ -151,6 +160,6 @@ class B(Base): class C(Base): - c_a = models.ForeignKey(A) - c_b = models.ForeignKey(B) + c_a = models.ForeignKey(A, models.CASCADE) + c_b = models.ForeignKey(B, models.CASCADE) is_published = models.BooleanField(default=False) diff --git a/tests/serializers/models.py b/tests/serializers/models.py index 4e2251ca18..6532ea953e 100644 --- a/tests/serializers/models.py +++ b/tests/serializers/models.py @@ -40,7 +40,7 @@ class CategoryMetaData(models.Model): @python_2_unicode_compatible class Category(models.Model): name = models.CharField(max_length=20) - meta_data = models.ForeignKey(CategoryMetaData, null=True, default=None) + meta_data = models.ForeignKey(CategoryMetaData, models.SET_NULL, null=True, default=None) class Meta: ordering = ('name',) @@ -62,7 +62,7 @@ class Author(models.Model): @python_2_unicode_compatible class Article(models.Model): - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) headline = models.CharField(max_length=50) pub_date = models.DateTimeField() categories = models.ManyToManyField(Category) @@ -77,7 +77,7 @@ class Article(models.Model): @python_2_unicode_compatible class AuthorProfile(models.Model): - author = models.OneToOneField(Author, primary_key=True) + author = models.OneToOneField(Author, models.CASCADE, primary_key=True) date_of_birth = models.DateField() def __str__(self): @@ -97,7 +97,7 @@ class Actor(models.Model): @python_2_unicode_compatible class Movie(models.Model): - actor = models.ForeignKey(Actor) + actor = models.ForeignKey(Actor, models.CASCADE) title = models.CharField(max_length=50) price = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00')) diff --git a/tests/serializers_regress/models.py b/tests/serializers_regress/models.py index 67cf0dddad..e781cb92c8 100644 --- a/tests/serializers_regress/models.py +++ b/tests/serializers_regress/models.py @@ -101,7 +101,7 @@ class TimeData(models.Model): class Tag(models.Model): """A tag on an item.""" data = models.SlugField() - content_type = models.ForeignKey(ContentType) + content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey() @@ -153,11 +153,11 @@ class UniqueAnchor(models.Model): class FKData(models.Model): - data = models.ForeignKey(Anchor, null=True) + data = models.ForeignKey(Anchor, models.SET_NULL, null=True) class FKDataNaturalKey(models.Model): - data = models.ForeignKey(NaturalKeyAnchor, null=True) + data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True) class M2MData(models.Model): @@ -166,11 +166,11 @@ class M2MData(models.Model): class O2OData(models.Model): # One to one field can't be null here, since it is a PK. - data = models.OneToOneField(Anchor, primary_key=True) + data = models.OneToOneField(Anchor, models.CASCADE, primary_key=True) class FKSelfData(models.Model): - data = models.ForeignKey('self', null=True) + data = models.ForeignKey('self', models.CASCADE, null=True) class M2MSelfData(models.Model): @@ -178,11 +178,11 @@ class M2MSelfData(models.Model): class FKDataToField(models.Model): - data = models.ForeignKey(UniqueAnchor, null=True, to_field='data') + data = models.ForeignKey(UniqueAnchor, models.SET_NULL, null=True, to_field='data') class FKDataToO2O(models.Model): - data = models.ForeignKey(O2OData, null=True) + data = models.ForeignKey(O2OData, models.SET_NULL, null=True) class M2MIntermediateData(models.Model): @@ -190,8 +190,8 @@ class M2MIntermediateData(models.Model): class Intermediate(models.Model): - left = models.ForeignKey(M2MIntermediateData) - right = models.ForeignKey(Anchor) + left = models.ForeignKey(M2MIntermediateData, models.CASCADE) + right = models.ForeignKey(Anchor, models.CASCADE) extra = models.CharField(max_length=30, blank=True, default="doesn't matter") # The following test classes are for validating the @@ -277,7 +277,7 @@ class UUIDData(models.Model): class FKToUUID(models.Model): - data = models.ForeignKey(UUIDData) + data = models.ForeignKey(UUIDData, models.CASCADE) class ComplexModel(models.Model): @@ -329,7 +329,7 @@ class InheritBaseModel(BaseModel): class ExplicitInheritBaseModel(BaseModel): - parent = models.OneToOneField(BaseModel) + parent = models.OneToOneField(BaseModel, models.CASCADE) child_data = models.IntegerField() diff --git a/tests/sites_framework/migrations/0001_initial.py b/tests/sites_framework/migrations/0001_initial.py index 5a4ac27961..78d26cab31 100644 --- a/tests/sites_framework/migrations/0001_initial.py +++ b/tests/sites_framework/migrations/0001_initial.py @@ -16,7 +16,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=50)), - ('places_this_article_should_appear', models.ForeignKey(to='sites.Site')), + ('places_this_article_should_appear', models.ForeignKey('sites.Site', models.CASCADE)), ], options={ 'abstract': False, @@ -28,7 +28,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=50)), - ('site', models.ForeignKey(to='sites.Site')), + ('site', models.ForeignKey('sites.Site', models.CASCADE)), ], options={ 'abstract': False, @@ -40,7 +40,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=50)), - ('sites', models.ManyToManyField(to='sites.Site')), + ('sites', models.ManyToManyField('sites.Site')), ], options={ 'abstract': False, diff --git a/tests/sites_framework/models.py b/tests/sites_framework/models.py index 23d39cec14..ed0f4443a1 100644 --- a/tests/sites_framework/models.py +++ b/tests/sites_framework/models.py @@ -23,11 +23,11 @@ class SyndicatedArticle(AbstractArticle): class ExclusiveArticle(AbstractArticle): - site = models.ForeignKey(Site) + site = models.ForeignKey(Site, models.CASCADE) class CustomArticle(AbstractArticle): - places_this_article_should_appear = models.ForeignKey(Site) + places_this_article_should_appear = models.ForeignKey(Site, models.CASCADE) objects = models.Manager() on_site = CurrentSiteManager("places_this_article_should_appear") diff --git a/tests/sites_framework/tests.py b/tests/sites_framework/tests.py index 911286adc1..681bfe5b03 100644 --- a/tests/sites_framework/tests.py +++ b/tests/sites_framework/tests.py @@ -42,7 +42,7 @@ class SitesFrameworkTestCase(TestCase): def test_invalid_name(self): class InvalidArticle(AbstractArticle): - site = models.ForeignKey(Site) + site = models.ForeignKey(Site, models.CASCADE) objects = models.Manager() on_site = CurrentSiteManager("places_this_article_should_appear") diff --git a/tests/string_lookup/models.py b/tests/string_lookup/models.py index 5761d80d49..775ec2faf0 100644 --- a/tests/string_lookup/models.py +++ b/tests/string_lookup/models.py @@ -17,9 +17,9 @@ class Foo(models.Model): @python_2_unicode_compatible class Bar(models.Model): name = models.CharField(max_length=50) - normal = models.ForeignKey(Foo, related_name='normal_foo') - fwd = models.ForeignKey("Whiz") - back = models.ForeignKey("Foo") + normal = models.ForeignKey(Foo, models.CASCADE, related_name='normal_foo') + fwd = models.ForeignKey("Whiz", models.CASCADE) + back = models.ForeignKey("Foo", models.CASCADE) def __str__(self): return "Bar %s" % self.place.name @@ -35,7 +35,7 @@ class Whiz(models.Model): @python_2_unicode_compatible class Child(models.Model): - parent = models.OneToOneField('Base') + parent = models.OneToOneField('Base', models.CASCADE) name = models.CharField(max_length=50) def __str__(self): diff --git a/tests/syndication_tests/models.py b/tests/syndication_tests/models.py index 166acd69ca..22b0f81fbb 100644 --- a/tests/syndication_tests/models.py +++ b/tests/syndication_tests/models.py @@ -21,7 +21,7 @@ class Entry(models.Model): @python_2_unicode_compatible class Article(models.Model): title = models.CharField(max_length=200) - entry = models.ForeignKey(Entry) + entry = models.ForeignKey(Entry, models.CASCADE) def __str__(self): return self.title diff --git a/tests/test_utils/models.py b/tests/test_utils/models.py index ca65a9a871..979b04855f 100644 --- a/tests/test_utils/models.py +++ b/tests/test_utils/models.py @@ -21,8 +21,8 @@ class Person(models.Model): @python_2_unicode_compatible class PossessedCar(models.Model): - car = models.ForeignKey(Car) - belongs_to = models.ForeignKey(Person) + car = models.ForeignKey(Car, models.CASCADE) + belongs_to = models.ForeignKey(Person, models.CASCADE) def __str__(self): return self.color diff --git a/tests/timezones/models.py b/tests/timezones/models.py index 73b198f32c..f7747d5937 100644 --- a/tests/timezones/models.py +++ b/tests/timezones/models.py @@ -15,7 +15,7 @@ class Session(models.Model): class SessionEvent(models.Model): dt = models.DateTimeField() - session = models.ForeignKey(Session, related_name='events') + session = models.ForeignKey(Session, models.CASCADE, related_name='events') class Timestamp(models.Model): diff --git a/tests/unmanaged_models/models.py b/tests/unmanaged_models/models.py index 61eb67a620..c41bdf5904 100644 --- a/tests/unmanaged_models/models.py +++ b/tests/unmanaged_models/models.py @@ -24,7 +24,7 @@ class A01(models.Model): @python_2_unicode_compatible class B01(models.Model): - fk_a = models.ForeignKey(A01) + fk_a = models.ForeignKey(A01, models.CASCADE) f_a = models.CharField(max_length=10, db_index=True) f_b = models.IntegerField() @@ -72,7 +72,7 @@ class B02(models.Model): db_table = 'b01' managed = False - fk_a = models.ForeignKey(A02) + fk_a = models.ForeignKey(A02, models.CASCADE) f_a = models.CharField(max_length=10, db_index=True) f_b = models.IntegerField() @@ -97,8 +97,8 @@ class C02(models.Model): class Intermediate(models.Model): - a02 = models.ForeignKey(A02, db_column="a01_id") - c02 = models.ForeignKey(C02, db_column="c01_id") + a02 = models.ForeignKey(A02, models.CASCADE, db_column="a01_id") + c02 = models.ForeignKey(C02, models.CASCADE, db_column="c01_id") class Meta: db_table = 'd01' diff --git a/tests/update/models.py b/tests/update/models.py index e0b391d0cd..648a773318 100644 --- a/tests/update/models.py +++ b/tests/update/models.py @@ -21,7 +21,7 @@ class DataPoint(models.Model): @python_2_unicode_compatible class RelatedPoint(models.Model): name = models.CharField(max_length=20) - data = models.ForeignKey(DataPoint) + data = models.ForeignKey(DataPoint, models.CASCADE) def __str__(self): return six.text_type(self.name) @@ -32,7 +32,7 @@ class A(models.Model): class B(models.Model): - a = models.ForeignKey(A) + a = models.ForeignKey(A, models.CASCADE) y = models.IntegerField(default=10) @@ -41,7 +41,7 @@ class C(models.Model): class D(C): - a = models.ForeignKey(A) + a = models.ForeignKey(A, models.CASCADE) class Foo(models.Model): @@ -49,4 +49,4 @@ class Foo(models.Model): class Bar(models.Model): - foo = models.ForeignKey(Foo, to_field='target') + foo = models.ForeignKey(Foo, models.CASCADE, to_field='target') diff --git a/tests/update_only_fields/models.py b/tests/update_only_fields/models.py index f2903b5bae..a3be5088a2 100644 --- a/tests/update_only_fields/models.py +++ b/tests/update_only_fields/models.py @@ -24,7 +24,7 @@ class Person(models.Model): class Employee(Person): employee_num = models.IntegerField(default=0) - profile = models.ForeignKey('Profile', related_name='profiles', null=True) + profile = models.ForeignKey('Profile', models.SET_NULL, related_name='profiles', null=True) accounts = models.ManyToManyField('Account', related_name='employees', blank=True) diff --git a/tests/utils_tests/models.py b/tests/utils_tests/models.py index de8f9e3803..700fcfcaf4 100644 --- a/tests/utils_tests/models.py +++ b/tests/utils_tests/models.py @@ -10,4 +10,4 @@ class Category(models.Model): class Thing(models.Model): name = models.CharField(max_length=100) - category = models.ForeignKey(Category) + category = models.ForeignKey(Category, models.CASCADE) diff --git a/tests/validation/models.py b/tests/validation/models.py index 1fe4aeb104..6b3d670000 100644 --- a/tests/validation/models.py +++ b/tests/validation/models.py @@ -16,9 +16,19 @@ class ModelToValidate(models.Model): name = models.CharField(max_length=100) created = models.DateTimeField(default=datetime.now) number = models.IntegerField(db_column='number_val') - parent = models.ForeignKey('self', blank=True, null=True, limit_choices_to={'number': 10}) + parent = models.ForeignKey( + 'self', + models.SET_NULL, + blank=True, null=True, + limit_choices_to={'number': 10}, + ) email = models.EmailField(blank=True) - ufm = models.ForeignKey('UniqueFieldsModel', to_field='unique_charfield', blank=True, null=True) + ufm = models.ForeignKey( + 'UniqueFieldsModel', + models.SET_NULL, + to_field='unique_charfield', + blank=True, null=True, + ) url = models.URLField(blank=True) f_with_custom_validator = models.IntegerField(blank=True, null=True, validators=[validate_answer_to_universe]) slug = models.SlugField(blank=True) @@ -70,7 +80,7 @@ class Author(models.Model): class Article(models.Model): title = models.CharField(max_length=100) - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) pub_date = models.DateTimeField(blank=True) def clean(self): diff --git a/tests/view_tests/models.py b/tests/view_tests/models.py index cb45d915f3..c891bcadee 100644 --- a/tests/view_tests/models.py +++ b/tests/view_tests/models.py @@ -25,7 +25,7 @@ class BaseArticle(models.Model): """ title = models.CharField(max_length=100) slug = models.SlugField() - author = models.ForeignKey(Author) + author = models.ForeignKey(Author, models.CASCADE) class Meta: abstract = True