class VersionSerializer(serializers.ModelSerializer): addon = CompatRelatedField(view_name='api_dispatch_detail', read_only=True, tastypie={'resource_name': 'app', 'api_name': 'apps'}) class Meta: model = Version fields = ('addon', '_developer_name', 'releasenotes', 'version') depth = 0 field_rename = { '_developer_name': 'developer_name', 'releasenotes': 'release_notes', 'addon': 'app' } def to_native(self, obj): native = super(VersionSerializer, self).to_native(obj) # Add non-field data to the response. native.update({ 'features': AppFeaturesSerializer().to_native(obj.features), 'is_current_version': obj.addon.current_version == obj, 'releasenotes': (unicode(obj.releasenotes) if obj.releasenotes else None), }) # Remap fields to friendlier, more backwards-compatible names. for old, new in self.Meta.field_rename.items(): native[new] = native[old] del native[old] return native
class UserSerializer(serializers.ModelSerializer): """ A wacky serializer type that unserializes PK numbers and serializes user fields. """ resource_uri = CompatRelatedField( view_name='api_dispatch_detail', read_only=True, tastypie={'resource_name': 'settings', 'api_name': 'account'}, source='*') class Meta: model = UserProfile fields = ('display_name', 'resource_uri') def field_from_native(self, data, files, field_name, into): try: value = data[field_name] except KeyError: if self.required: raise ValidationError(self.error_messages['required']) return if value in (None, ''): obj = None else: try: obj = UserProfile.objects.get(pk=value) except UserProfile.DoesNotExist: msg = "Invalid pk '%s' - object does not exist." % (data,) raise ValidationError(msg) into[self.source or field_name] = obj
def setUp(self): self.request = RequestFactory().get('/') self.field = CompatRelatedField( tastypie={'resource_name': 'app', 'api_name': 'apps'}, source='addon', slug_field='app_slug', read_only=True) # Mimic what DRF does when it initializes the fields on a serializer # by passing a context. self.field.context = {'request': self.request}
class PaymentAccountSerializer(HyperlinkedModelSerializer): addon = CompatRelatedField(source='addon', tastypie={ 'resource_name': 'app', 'api_name': 'apps' }, view_name='api_dispatch_detail') payment_account = CompatRelatedField(tastypie={ 'resource_name': 'account', 'api_name': 'payments' }, view_name='api_dispatch_detail') class Meta: model = AddonPaymentAccount fields = ('addon', 'payment_account', 'provider', 'created', 'modified') view_name = 'app-payment-account-detail' def validate(self, attrs): if attrs['addon'].premium_type in amo.ADDON_FREES: raise ValidationError('App must be a premium app.') return attrs
class UpsellSerializer(HyperlinkedModelSerializer): free = premium = CompatRelatedField(tastypie={ 'resource_name': 'app', 'api_name': 'apps' }, view_name='api_dispatch_detail') class Meta: model = AddonUpsell fields = ('free', 'premium', 'created', 'modified') view_name = 'app-upsell-detail' def validate(self, attrs): if attrs['free'].premium_type not in amo.ADDON_FREES: raise ValidationError('Upsell must be from a free app.') if attrs['premium'].premium_type in amo.ADDON_FREES: raise ValidationError('Upsell must be to a premium app.') return attrs
class AppSerializer(serializers.ModelSerializer): """ A wacky serializer type that unserializes PK numbers or slugs and serializes (some) app fields. """ resource_uri = CompatRelatedField(view_name='api_dispatch_detail', read_only=True, tastypie={ 'resource_name': 'app', 'api_name': 'apps' }, source='*') id = fields.IntegerField(source='pk') class Meta: model = Webapp fields = ('name', 'resource_uri', 'id') def field_from_native(self, data, files, field_name, into): try: value = data[field_name] except KeyError: if self.required: raise ValidationError(self.error_messages['required']) return if value in (None, ''): obj = None else: try: try: pk = int(value) obj = Webapp.objects.get(pk=pk) except ValueError: obj = Webapp.objects.get(app_slug=value) except Webapp.DoesNotExist: msg = "Invalid pk '%s' - object does not exist." % (data, ) raise ValidationError(msg) into[self.source or field_name] = obj
class TestCompatRelatedField(TestCase): def setUp(self): self.request = RequestFactory().get('/') self.field = CompatRelatedField( tastypie={'resource_name': 'app', 'api_name': 'apps'}, source='addon', slug_field='app_slug', read_only=True) # Mimic what DRF does when it initializes the fields on a serializer # by passing a context. self.field.context = {'request': self.request} def test_from_native(self): mock_queryset = Mock() self.field.queryset = mock_queryset self.field.from_native('slug') mock_queryset.get.assert_called_once_with(app_slug='slug') def test_from_native_string_pk(self): mock_queryset = Mock() self.field.queryset = mock_queryset self.field.from_native('1337') mock_queryset.get.assert_called_once_with(pk=1337) def test_from_native_pk(self): mock_queryset = Mock() self.field.queryset = mock_queryset self.field.from_native(1337) mock_queryset.get.assert_called_once_with(pk=1337) def test_from_native_url(self): mock_queryset = Mock() self.field.queryset = mock_queryset self.field.from_native('/api/v1/apps/app/1/') # Note: DRF doesn't convert back the pk to a string here. It's fine. mock_queryset.get.assert_called_once_with(pk='1') def test_from_native_url_with_protocol(self): mock_queryset = Mock() self.field.queryset = mock_queryset self.field.from_native('https://localhost/api/v1/apps/app/1/') # Note: DRF doesn't convert back the pk to a string here. It's fine. mock_queryset.get.assert_called_once_with(pk='1') def test_from_native_bad(self): with self.assertRaises(ValidationError): self.field.from_native(object()) def test_to_native(self): obj = Webapp(id=1) value = self.field.to_native(obj) eq_(value, '/api/v1/apps/app/1/')