mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	This is a big internal change, but mostly backwards compatible with existing code. Also adds a couple of new features. Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658 git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Tests for field subclassing.
 | |
| """
 | |
| 
 | |
| from django.db import models
 | |
| from django.utils.encoding import force_unicode
 | |
| from django.core import serializers
 | |
| from django.core.exceptions import FieldError
 | |
| 
 | |
| class Small(object):
 | |
|     """
 | |
|     A simple class to show that non-trivial Python objects can be used as
 | |
|     attributes.
 | |
|     """
 | |
|     def __init__(self, first, second):
 | |
|         self.first, self.second = first, second
 | |
| 
 | |
|     def __unicode__(self):
 | |
|         return u'%s%s' % (force_unicode(self.first), force_unicode(self.second))
 | |
| 
 | |
|     def __str__(self):
 | |
|         return unicode(self).encode('utf-8')
 | |
| 
 | |
| class SmallField(models.Field):
 | |
|     """
 | |
|     Turns the "Small" class into a Django field. Because of the similarities
 | |
|     with normal character fields and the fact that Small.__unicode__ does
 | |
|     something sensible, we don't need to implement a lot here.
 | |
|     """
 | |
|     __metaclass__ = models.SubfieldBase
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         kwargs['max_length'] = 2
 | |
|         super(SmallField, self).__init__(*args, **kwargs)
 | |
| 
 | |
|     def get_internal_type(self):
 | |
|         return 'CharField'
 | |
| 
 | |
|     def to_python(self, value):
 | |
|         if isinstance(value, Small):
 | |
|             return value
 | |
|         return Small(value[0], value[1])
 | |
| 
 | |
|     def get_db_prep_save(self, value):
 | |
|         return unicode(value)
 | |
| 
 | |
|     def get_db_prep_lookup(self, lookup_type, value):
 | |
|         if lookup_type == 'exact':
 | |
|             return force_unicode(value)
 | |
|         if lookup_type == 'in':
 | |
|             return [force_unicode(v) for v in value]
 | |
|         if lookup_type == 'isnull':
 | |
|             return []
 | |
|         raise FieldError('Invalid lookup type: %r' % lookup_type)
 | |
| 
 | |
|     def flatten_data(self, follow, obj=None):
 | |
|         return {self.attname: force_unicode(self._get_val_from_obj(obj))}
 | |
| 
 | |
| class MyModel(models.Model):
 | |
|     name = models.CharField(max_length=10)
 | |
|     data = SmallField('small field')
 | |
| 
 | |
|     def __unicode__(self):
 | |
|         return force_unicode(self.name)
 | |
| 
 | |
| __test__ = {'API_TESTS': ur"""
 | |
| # Creating a model with custom fields is done as per normal.
 | |
| >>> s = Small(1, 2)
 | |
| >>> print s
 | |
| 12
 | |
| >>> m = MyModel(name='m', data=s)
 | |
| >>> m.save()
 | |
| 
 | |
| # Custom fields still have normal field's attributes.
 | |
| >>> m._meta.get_field('data').verbose_name
 | |
| 'small field'
 | |
| 
 | |
| # The m.data attribute has been initialised correctly. It's a Small object.
 | |
| >>> m.data.first, m.data.second
 | |
| (1, 2)
 | |
| 
 | |
| # The data loads back from the database correctly and 'data' has the right type.
 | |
| >>> m1 = MyModel.objects.get(pk=m.pk)
 | |
| >>> isinstance(m1.data, Small)
 | |
| True
 | |
| >>> print m1.data
 | |
| 12
 | |
| 
 | |
| # We can do normal filtering on the custom field (and will get an error when we
 | |
| # use a lookup type that does not make sense).
 | |
| >>> s1 = Small(1, 3)
 | |
| >>> s2 = Small('a', 'b')
 | |
| >>> MyModel.objects.filter(data__in=[s, s1, s2])
 | |
| [<MyModel: m>]
 | |
| >>> MyModel.objects.filter(data__lt=s)
 | |
| Traceback (most recent call last):
 | |
| ...
 | |
| FieldError: Invalid lookup type: 'lt'
 | |
| 
 | |
| # Serialization works, too.
 | |
| >>> stream = serializers.serialize("json", MyModel.objects.all())
 | |
| >>> stream
 | |
| '[{"pk": 1, "model": "field_subclassing.mymodel", "fields": {"data": "12", "name": "m"}}]'
 | |
| >>> obj = list(serializers.deserialize("json", stream))[0]
 | |
| >>> obj.object == m
 | |
| True
 | |
| 
 | |
| # Test retrieving custom field data
 | |
| >>> m.delete()
 | |
| >>> m1 = MyModel(name="1", data=Small(1, 2))
 | |
| >>> m1.save()
 | |
| >>> m2 = MyModel(name="2", data=Small(2, 3))
 | |
| >>> m2.save()
 | |
| >>> for m in MyModel.objects.all(): print unicode(m.data)
 | |
| 12
 | |
| 23
 | |
| """}
 |