Clean up existing deprecation warnings. (#4166)

* Add Meta.fields = '__all__' to serializer classes where required.
* Add explicit on_delete=models.CASCADE to ForeignKey fields.
* Use '.remote_field' and '.model' in preference to '.rel' and '.to' when inspecting model fields.
* Use new value_from_object in preference to internal _get_val_from_obj
This commit is contained in:
Tom Christie 2016-06-02 14:39:10 +01:00
parent 53a356a380
commit 9c996d7d2a
19 changed files with 137 additions and 61 deletions

View File

@ -17,7 +17,7 @@ class Migration(migrations.Migration):
fields=[
('key', models.CharField(primary_key=True, serialize=False, max_length=40)),
('created', models.DateTimeField(auto_now_add=True)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token')),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token', on_delete=models.CASCADE)),
],
options={
},

View File

@ -29,6 +29,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='token',
name='user',
field=models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name='User', related_name='auth_token'),
field=models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name='User', related_name='auth_token', on_delete=models.CASCADE),
),
]

View File

@ -6,9 +6,13 @@ versions of Django/Python, and compatibility wrappers around optional packages.
# flake8: noqa
from __future__ import unicode_literals
import inspect
import django
from django.apps import apps
from django.conf import settings
from django.db import connection, transaction
from django.core.exceptions import ImproperlyConfigured
from django.db import connection, models, transaction
from django.template import Context, RequestContext, Template
from django.utils import six
from django.views.generic import View
@ -58,6 +62,7 @@ def distinct(queryset, base):
return queryset.distinct()
# Obtaining manager instances and names from model options differs after 1.10.
def get_names_and_managers(options):
if django.VERSION >= (1, 10):
# Django 1.10 onwards provides a `.managers` property on the Options.
@ -75,6 +80,54 @@ def get_names_and_managers(options):
]
# field.rel is deprecated from 1.9 onwards
def get_remote_field(field, **kwargs):
if 'default' in kwargs:
if django.VERSION < (1, 9):
return getattr(field, 'rel', kwargs['default'])
return getattr(field, 'remote_field', kwargs['default'])
if django.VERSION < (1, 9):
return field.rel
return field.remote_field
def _resolve_model(obj):
"""
Resolve supplied `obj` to a Django model class.
`obj` must be a Django model class itself, or a string
representation of one. Useful in situations like GH #1225 where
Django may not have resolved a string-based reference to a model in
another model's foreign key definition.
String representations should have the format:
'appname.ModelName'
"""
if isinstance(obj, six.string_types) and len(obj.split('.')) == 2:
app_name, model_name = obj.split('.')
resolved_model = apps.get_model(app_name, model_name)
if resolved_model is None:
msg = "Django did not return a model for {0}.{1}"
raise ImproperlyConfigured(msg.format(app_name, model_name))
return resolved_model
elif inspect.isclass(obj) and issubclass(obj, models.Model):
return obj
raise ValueError("{0} is not a Django model".format(obj))
def get_related_model(field):
if django.VERSION < (1, 9):
return _resolve_model(field.rel.to)
return field.remote_field.model
def value_from_object(field, obj):
if django.VERSION < (1, 9):
return field._get_val_from_obj(obj)
field.value_from_object(obj)
# contrib.postgres only supported from 1.8 onwards.
try:
from django.contrib.postgres import fields as postgres_fields

View File

@ -30,7 +30,9 @@ from django.utils.ipv6 import clean_ipv6_address
from django.utils.translation import ugettext_lazy as _
from rest_framework import ISO_8601
from rest_framework.compat import unicode_repr, unicode_to_repr
from rest_framework.compat import (
get_remote_field, unicode_repr, unicode_to_repr, value_from_object
)
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings
from rest_framework.utils import html, humanize_datetime, representation
@ -1674,7 +1676,7 @@ class ModelField(Field):
self.validators.append(MaxLengthValidator(max_length, message=message))
def to_internal_value(self, data):
rel = getattr(self.model_field, 'rel', None)
rel = get_remote_field(self.model_field, default=None)
if rel is not None:
return rel.to._meta.get_field(rel.field_name).to_python(data)
return self.model_field.to_python(data)
@ -1685,7 +1687,7 @@ class ModelField(Field):
return obj
def to_representation(self, obj):
value = self.model_field._get_val_from_obj(obj)
value = value_from_object(self.model_field, obj)
if is_protected_type(value):
return value
return self.model_field.value_to_string(obj)

View File

@ -1153,6 +1153,7 @@ class ModelSerializer(Serializer):
class Meta:
model = relation_info.related_model
depth = nested_depth - 1
fields = '__all__'
field_class = NestedSerializer
field_kwargs = get_nested_relation_kwargs(relation_info)
@ -1469,6 +1470,7 @@ class HyperlinkedModelSerializer(ModelSerializer):
class Meta:
model = relation_info.related_model
depth = nested_depth - 1
fields = '__all__'
field_class = NestedSerializer
field_kwargs = get_nested_relation_kwargs(relation_info)

View File

@ -5,13 +5,9 @@ relationships and their associated metadata.
Usage: `get_field_info(model)` returns a `FieldInfo` instance.
"""
import inspect
from collections import OrderedDict, namedtuple
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils import six
from rest_framework.compat import get_related_model, get_remote_field
FieldInfo = namedtuple('FieldResult', [
'pk', # Model field instance
@ -31,30 +27,6 @@ RelationInfo = namedtuple('RelationInfo', [
])
def _resolve_model(obj):
"""
Resolve supplied `obj` to a Django model class.
`obj` must be a Django model class itself, or a string
representation of one. Useful in situations like GH #1225 where
Django may not have resolved a string-based reference to a model in
another model's foreign key definition.
String representations should have the format:
'appname.ModelName'
"""
if isinstance(obj, six.string_types) and len(obj.split('.')) == 2:
app_name, model_name = obj.split('.')
resolved_model = apps.get_model(app_name, model_name)
if resolved_model is None:
msg = "Django did not return a model for {0}.{1}"
raise ImproperlyConfigured(msg.format(app_name, model_name))
return resolved_model
elif inspect.isclass(obj) and issubclass(obj, models.Model):
return obj
raise ValueError("{0} is not a Django model".format(obj))
def get_field_info(model):
"""
Given a model class, returns a `FieldInfo` instance, which is a
@ -76,16 +48,19 @@ def get_field_info(model):
def _get_pk(opts):
pk = opts.pk
while pk.rel and pk.rel.parent_link:
rel = get_remote_field(pk)
while rel and rel.parent_link:
# If model is a child via multi-table inheritance, use parent's pk.
pk = pk.rel.to._meta.pk
pk = get_related_model(pk)._meta.pk
rel = get_remote_field(pk)
return pk
def _get_fields(opts):
fields = OrderedDict()
for field in [field for field in opts.fields if field.serialize and not field.rel]:
for field in [field for field in opts.fields if field.serialize and not get_remote_field(field)]:
fields[field.name] = field
return fields
@ -100,10 +75,10 @@ def _get_forward_relationships(opts):
Returns an `OrderedDict` of field names to `RelationInfo`.
"""
forward_relations = OrderedDict()
for field in [field for field in opts.fields if field.serialize and field.rel]:
for field in [field for field in opts.fields if field.serialize and get_remote_field(field)]:
forward_relations[field.name] = RelationInfo(
model_field=field,
related_model=_resolve_model(field.rel.to),
related_model=get_related_model(field),
to_many=False,
to_field=_get_to_field(field),
has_through_model=False
@ -113,12 +88,12 @@ def _get_forward_relationships(opts):
for field in [field for field in opts.many_to_many if field.serialize]:
forward_relations[field.name] = RelationInfo(
model_field=field,
related_model=_resolve_model(field.rel.to),
related_model=get_related_model(field),
to_many=True,
# manytomany do not have to_fields
to_field=None,
has_through_model=(
not field.rel.through._meta.auto_created
not get_remote_field(field).through._meta.auto_created
)
)
@ -141,7 +116,7 @@ def _get_reverse_relationships(opts):
reverse_relations[accessor_name] = RelationInfo(
model_field=None,
related_model=related,
to_many=relation.field.rel.multiple,
to_many=get_remote_field(relation.field).multiple,
to_field=_get_to_field(relation.field),
has_through_model=False
)
@ -158,8 +133,8 @@ def _get_reverse_relationships(opts):
# manytomany do not have to_fields
to_field=None,
has_through_model=(
(getattr(relation.field.rel, 'through', None) is not None) and
not relation.field.rel.through._meta.auto_created
(getattr(get_remote_field(relation.field), 'through', None) is not None) and
not get_remote_field(relation.field).through._meta.auto_created
)
)

View File

@ -29,7 +29,7 @@ factory = APIRequestFactory()
class CustomToken(models.Model):
key = models.CharField(max_length=40, primary_key=True)
user = models.OneToOneField(User)
user = models.OneToOneField(User, on_delete=models.CASCADE)
class CustomTokenAuthentication(TokenAuthentication):

View File

@ -26,6 +26,7 @@ if django_filters:
class FilterableItemSerializer(serializers.ModelSerializer):
class Meta:
model = FilterableItem
fields = '__all__'
# Basic filter on a list view.
class FilterFieldsRootView(generics.ListCreateAPIView):
@ -336,6 +337,7 @@ class SearchFilterModel(models.Model):
class SearchFilterSerializer(serializers.ModelSerializer):
class Meta:
model = SearchFilterModel
fields = '__all__'
class SearchFilterTests(TestCase):
@ -461,6 +463,7 @@ class SearchFilterModelM2M(models.Model):
class SearchFilterM2MSerializer(serializers.ModelSerializer):
class Meta:
model = SearchFilterModelM2M
fields = '__all__'
class SearchFilterM2MTests(TestCase):
@ -504,13 +507,13 @@ class OrderingFilterModel(models.Model):
class OrderingFilterRelatedModel(models.Model):
related_object = models.ForeignKey(OrderingFilterModel,
related_name="relateds")
related_object = models.ForeignKey(OrderingFilterModel, related_name="relateds", on_delete=models.CASCADE)
class OrderingFilterSerializer(serializers.ModelSerializer):
class Meta:
model = OrderingFilterModel
fields = '__all__'
class DjangoFilterOrderingModel(models.Model):
@ -524,6 +527,7 @@ class DjangoFilterOrderingModel(models.Model):
class DjangoFilterOrderingSerializer(serializers.ModelSerializer):
class Meta:
model = DjangoFilterOrderingModel
fields = '__all__'
class DjangoFilterOrderingTests(TestCase):

View File

@ -33,11 +33,13 @@ class Comment(RESTFrameworkModel):
class BasicSerializer(serializers.ModelSerializer):
class Meta:
model = BasicModel
fields = '__all__'
class ForeignKeySerializer(serializers.ModelSerializer):
class Meta:
model = ForeignKeySource
fields = '__all__'
class SlugSerializer(serializers.ModelSerializer):
@ -414,6 +416,7 @@ class ClassASerializer(serializers.ModelSerializer):
class Meta:
model = ClassA
fields = '__all__'
class ExampleView(generics.ListCreateAPIView):
@ -461,6 +464,7 @@ class DynamicSerializerView(generics.ListCreateAPIView):
class DynamicSerializer(serializers.ModelSerializer):
class Meta:
model = TwoFieldModel
fields = '__all__'
return DynamicSerializer

View File

@ -300,6 +300,7 @@ class TestModelSerializerMetadata(TestCase):
class Meta:
model = Parent
fields = '__all__'
class ExampleView(views.APIView):
"""Example view."""

View File

@ -141,6 +141,7 @@ class TestRegularFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RegularFieldsModel
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -173,6 +174,7 @@ class TestRegularFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = FieldOptionsModel
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -306,6 +308,7 @@ class TestRegularFieldMappings(TestCase):
class Meta:
model = RegularFieldsModel
fields = '__all__'
class ChildSerializer(TestSerializer):
missing = serializers.ReadOnlyField()
@ -320,6 +323,7 @@ class TestRegularFieldMappings(TestCase):
class ExampleSerializer(serializers.ModelSerializer):
class Meta:
model = ChoicesModel
fields = '__all__'
ExampleSerializer()
@ -327,6 +331,7 @@ class TestRegularFieldMappings(TestCase):
class ImplicitFieldsSerializer(serializers.ModelSerializer):
class Meta:
model = RegularFieldsModel
fields = '__all__'
class ExplicitFieldsSerializer(serializers.ModelSerializer):
class Meta:
@ -350,6 +355,7 @@ class TestDurationFieldMapping(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DurationFieldModel
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -367,6 +373,7 @@ class TestGenericIPAddressFieldValidation(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = IPAddressFieldModel
fields = '__all__'
s = TestSerializer(data={'address': 'not an ip address'})
self.assertFalse(s.is_valid())
@ -396,20 +403,20 @@ class ThroughTargetModel(models.Model):
class Supplementary(models.Model):
extra = models.IntegerField()
forwards = models.ForeignKey('ThroughTargetModel')
backwards = models.ForeignKey('RelationalModel')
forwards = models.ForeignKey('ThroughTargetModel', on_delete=models.CASCADE)
backwards = models.ForeignKey('RelationalModel', on_delete=models.CASCADE)
class RelationalModel(models.Model):
foreign_key = models.ForeignKey(ForeignKeyTargetModel, related_name='reverse_foreign_key')
foreign_key = models.ForeignKey(ForeignKeyTargetModel, related_name='reverse_foreign_key', on_delete=models.CASCADE)
many_to_many = models.ManyToManyField(ManyToManyTargetModel, related_name='reverse_many_to_many')
one_to_one = models.OneToOneField(OneToOneTargetModel, related_name='reverse_one_to_one')
one_to_one = models.OneToOneField(OneToOneTargetModel, related_name='reverse_one_to_one', on_delete=models.CASCADE)
through = models.ManyToManyField(ThroughTargetModel, through=Supplementary, related_name='reverse_through')
class UniqueTogetherModel(models.Model):
foreign_key = models.ForeignKey(ForeignKeyTargetModel, related_name='unique_foreign_key')
one_to_one = models.OneToOneField(OneToOneTargetModel, related_name='unique_one_to_one')
foreign_key = models.ForeignKey(ForeignKeyTargetModel, related_name='unique_foreign_key', on_delete=models.CASCADE)
one_to_one = models.OneToOneField(OneToOneTargetModel, related_name='unique_one_to_one', on_delete=models.CASCADE)
class Meta:
unique_together = ("foreign_key", "one_to_one")
@ -420,6 +427,7 @@ class TestRelationalFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RelationalModel
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -436,6 +444,7 @@ class TestRelationalFieldMappings(TestCase):
class Meta:
model = RelationalModel
depth = 1
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -459,6 +468,7 @@ class TestRelationalFieldMappings(TestCase):
class TestSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = RelationalModel
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -475,6 +485,7 @@ class TestRelationalFieldMappings(TestCase):
class Meta:
model = RelationalModel
depth = 1
fields = '__all__'
expected = dedent("""
TestSerializer():
@ -499,6 +510,8 @@ class TestRelationalFieldMappings(TestCase):
class Meta:
model = UniqueTogetherModel
depth = 1
fields = '__all__'
expected = dedent("""
TestSerializer():
url = HyperlinkedIdentityField(view_name='uniquetogethermodel-detail')
@ -585,7 +598,7 @@ class DisplayValueTargetModel(models.Model):
class DisplayValueModel(models.Model):
color = models.ForeignKey(DisplayValueTargetModel)
color = models.ForeignKey(DisplayValueTargetModel, on_delete=models.CASCADE)
class TestRelationalFieldDisplayValue(TestCase):
@ -600,6 +613,7 @@ class TestRelationalFieldDisplayValue(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DisplayValueModel
fields = '__all__'
serializer = TestSerializer()
expected = OrderedDict([('1', 'Red Color'), ('2', 'Yellow Color'), ('3', 'Green Color')])
@ -615,6 +629,7 @@ class TestRelationalFieldDisplayValue(TestCase):
class Meta:
model = DisplayValueModel
fields = '__all__'
serializer = TestSerializer()
expected = OrderedDict([('1', 'My Red Color'), ('2', 'My Yellow Color'), ('3', 'My Green Color')])
@ -645,6 +660,7 @@ class TestIntegration(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RelationalModel
fields = '__all__'
serializer = TestSerializer(self.instance)
expected = {
@ -660,6 +676,7 @@ class TestIntegration(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RelationalModel
fields = '__all__'
new_foreign_key = ForeignKeyTargetModel.objects.create(
name='foreign_key'
@ -707,6 +724,7 @@ class TestIntegration(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RelationalModel
fields = '__all__'
new_foreign_key = ForeignKeyTargetModel.objects.create(
name='foreign_key'
@ -875,6 +893,7 @@ class TestDecimalFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DecimalFieldModel
fields = '__all__'
serializer = TestSerializer()
@ -888,6 +907,7 @@ class TestDecimalFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DecimalFieldModel
fields = '__all__'
serializer = TestSerializer()
@ -901,6 +921,7 @@ class TestDecimalFieldMappings(TestCase):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DecimalFieldModel
fields = '__all__'
serializer = TestSerializer()

View File

@ -17,7 +17,7 @@ class ChildModel(ParentModel):
class AssociatedModel(RESTFrameworkModel):
ref = models.OneToOneField(ParentModel, primary_key=True)
ref = models.OneToOneField(ParentModel, primary_key=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
@ -25,11 +25,13 @@ class AssociatedModel(RESTFrameworkModel):
class DerivedModelSerializer(serializers.ModelSerializer):
class Meta:
model = ChildModel
fields = '__all__'
class AssociatedModelSerializer(serializers.ModelSerializer):
class Meta:
model = AssociatedModel
fields = '__all__'
# Tests

View File

@ -24,6 +24,7 @@ factory = APIRequestFactory()
class BasicSerializer(serializers.ModelSerializer):
class Meta:
model = BasicModel
fields = '__all__'
class RootView(generics.ListCreateAPIView):
@ -215,6 +216,7 @@ class BasicPermModel(models.Model):
class BasicPermSerializer(serializers.ModelSerializer):
class Meta:
model = BasicPermModel
fields = '__all__'
# Custom object-level permission, that includes 'view' permissions

View File

@ -17,7 +17,7 @@ class Tag(models.Model):
Tags have a descriptive slug, and are attached to an arbitrary object.
"""
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
tagged_item = GenericForeignKey('content_type', 'object_id')

View File

@ -15,6 +15,7 @@ class ForeignKeyTargetSerializer(serializers.ModelSerializer):
class Meta:
model = ForeignKeyTarget
fields = '__all__'
class ForeignKeySourceSerializer(serializers.ModelSerializer):
@ -25,6 +26,7 @@ class ForeignKeySourceSerializer(serializers.ModelSerializer):
class Meta:
model = ForeignKeySource
fields = '__all__'
class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
@ -36,6 +38,7 @@ class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
class Meta:
model = NullableForeignKeySource
fields = '__all__'
# TODO: M2M Tests, FKTests (Non-nullable), One2One

View File

@ -18,6 +18,7 @@ from tests.models import BasicModel
class BasicModelSerializer(serializers.ModelSerializer):
class Meta:
model = BasicModel
fields = '__all__'
class MockPickleRenderer(BaseRenderer):

View File

@ -6,8 +6,8 @@ from django.test import TestCase, override_settings
from django.utils import six
import rest_framework.utils.model_meta
from rest_framework.compat import _resolve_model
from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework.utils.model_meta import _resolve_model
from rest_framework.views import APIView
from tests.models import BasicModel
@ -166,16 +166,16 @@ class ResolveModelWithPatchedDjangoTests(TestCase):
def setUp(self):
"""Monkeypatch get_model."""
self.get_model = rest_framework.utils.model_meta.apps.get_model
self.get_model = rest_framework.compat.apps.get_model
def get_model(app_label, model_name):
return None
rest_framework.utils.model_meta.apps.get_model = get_model
rest_framework.compat.apps.get_model = get_model
def tearDown(self):
"""Revert monkeypatching."""
rest_framework.utils.model_meta.apps.get_model = self.get_model
rest_framework.compat.apps.get_model = self.get_model
def test_blows_up_if_model_does_not_resolve(self):
with self.assertRaises(ImproperlyConfigured):

View File

@ -125,6 +125,7 @@ class ValidationMaxValueValidatorModel(models.Model):
class ValidationMaxValueValidatorModelSerializer(serializers.ModelSerializer):
class Meta:
model = ValidationMaxValueValidatorModel
fields = '__all__'
class UpdateMaxValueValidationModel(generics.RetrieveUpdateDestroyAPIView):

View File

@ -21,6 +21,7 @@ class UniquenessModel(models.Model):
class UniquenessSerializer(serializers.ModelSerializer):
class Meta:
model = UniquenessModel
fields = '__all__'
class RelatedModel(models.Model):
@ -44,6 +45,7 @@ class AnotherUniquenessModel(models.Model):
class AnotherUniquenessSerializer(serializers.ModelSerializer):
class Meta:
model = AnotherUniquenessModel
fields = '__all__'
class TestUniquenessValidation(TestCase):
@ -134,11 +136,13 @@ class NullUniquenessTogetherModel(models.Model):
class UniquenessTogetherSerializer(serializers.ModelSerializer):
class Meta:
model = UniquenessTogetherModel
fields = '__all__'
class NullUniquenessTogetherSerializer(serializers.ModelSerializer):
class Meta:
model = NullUniquenessTogetherModel
fields = '__all__'
class TestUniquenessTogetherValidation(TestCase):
@ -275,6 +279,7 @@ class UniqueForDateModel(models.Model):
class UniqueForDateSerializer(serializers.ModelSerializer):
class Meta:
model = UniqueForDateModel
fields = '__all__'
class TestUniquenessForDateValidation(TestCase):