models.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import json
  2. import os
  3. import tempfile
  4. import uuid
  5. from django.contrib.contenttypes.fields import (
  6. GenericForeignKey, GenericRelation,
  7. )
  8. from django.contrib.contenttypes.models import ContentType
  9. from django.core.files.storage import FileSystemStorage
  10. from django.core.serializers.json import DjangoJSONEncoder
  11. from django.db import models
  12. from django.db.models.fields.files import ImageFieldFile
  13. from django.utils.translation import gettext_lazy as _
  14. try:
  15. from PIL import Image
  16. except ImportError:
  17. Image = None
  18. class Foo(models.Model):
  19. a = models.CharField(max_length=10)
  20. d = models.DecimalField(max_digits=5, decimal_places=3)
  21. def get_foo():
  22. return Foo.objects.get(id=1).pk
  23. class Bar(models.Model):
  24. b = models.CharField(max_length=10)
  25. a = models.ForeignKey(Foo, models.CASCADE, default=get_foo, related_name='bars')
  26. class Whiz(models.Model):
  27. CHOICES = (
  28. ('Group 1', (
  29. (1, 'First'),
  30. (2, 'Second'),
  31. )
  32. ),
  33. ('Group 2', (
  34. (3, 'Third'),
  35. (4, 'Fourth'),
  36. )
  37. ),
  38. (0, 'Other'),
  39. (5, _('translated')),
  40. )
  41. c = models.IntegerField(choices=CHOICES, null=True)
  42. class WhizDelayed(models.Model):
  43. c = models.IntegerField(choices=(), null=True)
  44. # Contrived way of adding choices later.
  45. WhizDelayed._meta.get_field('c').choices = Whiz.CHOICES
  46. class WhizIter(models.Model):
  47. c = models.IntegerField(choices=iter(Whiz.CHOICES), null=True)
  48. class WhizIterEmpty(models.Model):
  49. c = models.CharField(choices=iter(()), blank=True, max_length=1)
  50. class Choiceful(models.Model):
  51. no_choices = models.IntegerField(null=True)
  52. empty_choices = models.IntegerField(choices=(), null=True)
  53. with_choices = models.IntegerField(choices=[(1, 'A')], null=True)
  54. empty_choices_bool = models.BooleanField(choices=())
  55. empty_choices_text = models.TextField(choices=())
  56. class BigD(models.Model):
  57. d = models.DecimalField(max_digits=32, decimal_places=30)
  58. class FloatModel(models.Model):
  59. size = models.FloatField()
  60. class BigS(models.Model):
  61. s = models.SlugField(max_length=255)
  62. class UnicodeSlugField(models.Model):
  63. s = models.SlugField(max_length=255, allow_unicode=True)
  64. class AutoModel(models.Model):
  65. value = models.AutoField(primary_key=True)
  66. class BigAutoModel(models.Model):
  67. value = models.BigAutoField(primary_key=True)
  68. class SmallAutoModel(models.Model):
  69. value = models.SmallAutoField(primary_key=True)
  70. class SmallIntegerModel(models.Model):
  71. value = models.SmallIntegerField()
  72. class IntegerModel(models.Model):
  73. value = models.IntegerField()
  74. class BigIntegerModel(models.Model):
  75. value = models.BigIntegerField()
  76. null_value = models.BigIntegerField(null=True, blank=True)
  77. class PositiveBigIntegerModel(models.Model):
  78. value = models.PositiveBigIntegerField()
  79. class PositiveSmallIntegerModel(models.Model):
  80. value = models.PositiveSmallIntegerField()
  81. class PositiveIntegerModel(models.Model):
  82. value = models.PositiveIntegerField()
  83. class Post(models.Model):
  84. title = models.CharField(max_length=100)
  85. body = models.TextField()
  86. class NullBooleanModel(models.Model):
  87. nbfield = models.BooleanField(null=True, blank=True)
  88. nbfield_old = models.NullBooleanField()
  89. class BooleanModel(models.Model):
  90. bfield = models.BooleanField()
  91. string = models.CharField(max_length=10, default='abc')
  92. class DateTimeModel(models.Model):
  93. d = models.DateField()
  94. dt = models.DateTimeField()
  95. t = models.TimeField()
  96. class DurationModel(models.Model):
  97. field = models.DurationField()
  98. class NullDurationModel(models.Model):
  99. field = models.DurationField(null=True)
  100. class PrimaryKeyCharModel(models.Model):
  101. string = models.CharField(max_length=10, primary_key=True)
  102. class FksToBooleans(models.Model):
  103. """Model with FKs to models with {Null,}BooleanField's, #15040"""
  104. bf = models.ForeignKey(BooleanModel, models.CASCADE)
  105. nbf = models.ForeignKey(NullBooleanModel, models.CASCADE)
  106. class FkToChar(models.Model):
  107. """Model with FK to a model with a CharField primary key, #19299"""
  108. out = models.ForeignKey(PrimaryKeyCharModel, models.CASCADE)
  109. class RenamedField(models.Model):
  110. modelname = models.IntegerField(name="fieldname", choices=((1, 'One'),))
  111. class VerboseNameField(models.Model):
  112. id = models.AutoField("verbose pk", primary_key=True)
  113. field1 = models.BigIntegerField("verbose field1")
  114. field2 = models.BooleanField("verbose field2", default=False)
  115. field3 = models.CharField("verbose field3", max_length=10)
  116. field4 = models.DateField("verbose field4")
  117. field5 = models.DateTimeField("verbose field5")
  118. field6 = models.DecimalField("verbose field6", max_digits=6, decimal_places=1)
  119. field7 = models.EmailField("verbose field7")
  120. field8 = models.FileField("verbose field8", upload_to="unused")
  121. field9 = models.FilePathField("verbose field9")
  122. field10 = models.FloatField("verbose field10")
  123. # Don't want to depend on Pillow in this test
  124. # field_image = models.ImageField("verbose field")
  125. field11 = models.IntegerField("verbose field11")
  126. field12 = models.GenericIPAddressField("verbose field12", protocol="ipv4")
  127. field13 = models.NullBooleanField("verbose field13")
  128. field14 = models.PositiveIntegerField("verbose field14")
  129. field15 = models.PositiveSmallIntegerField("verbose field15")
  130. field16 = models.SlugField("verbose field16")
  131. field17 = models.SmallIntegerField("verbose field17")
  132. field18 = models.TextField("verbose field18")
  133. field19 = models.TimeField("verbose field19")
  134. field20 = models.URLField("verbose field20")
  135. field21 = models.UUIDField("verbose field21")
  136. field22 = models.DurationField("verbose field22")
  137. class GenericIPAddress(models.Model):
  138. ip = models.GenericIPAddressField(null=True, protocol='ipv4')
  139. ###############################################################################
  140. # These models aren't used in any test, just here to ensure they validate
  141. # successfully.
  142. # See ticket #16570.
  143. class DecimalLessThanOne(models.Model):
  144. d = models.DecimalField(max_digits=3, decimal_places=3)
  145. # See ticket #18389.
  146. class FieldClassAttributeModel(models.Model):
  147. field_class = models.CharField
  148. ###############################################################################
  149. class DataModel(models.Model):
  150. short_data = models.BinaryField(max_length=10, default=b'\x08')
  151. data = models.BinaryField()
  152. ###############################################################################
  153. # FileField
  154. class Document(models.Model):
  155. myfile = models.FileField(upload_to='unused', unique=True)
  156. ###############################################################################
  157. # ImageField
  158. # If Pillow available, do these tests.
  159. if Image:
  160. class TestImageFieldFile(ImageFieldFile):
  161. """
  162. Custom Field File class that records whether or not the underlying file
  163. was opened.
  164. """
  165. def __init__(self, *args, **kwargs):
  166. self.was_opened = False
  167. super().__init__(*args, **kwargs)
  168. def open(self):
  169. self.was_opened = True
  170. super().open()
  171. class TestImageField(models.ImageField):
  172. attr_class = TestImageFieldFile
  173. # Set up a temp directory for file storage.
  174. temp_storage_dir = tempfile.mkdtemp()
  175. temp_storage = FileSystemStorage(temp_storage_dir)
  176. temp_upload_to_dir = os.path.join(temp_storage.location, 'tests')
  177. class Person(models.Model):
  178. """
  179. Model that defines an ImageField with no dimension fields.
  180. """
  181. name = models.CharField(max_length=50)
  182. mugshot = TestImageField(storage=temp_storage, upload_to='tests')
  183. class AbstractPersonWithHeight(models.Model):
  184. """
  185. Abstract model that defines an ImageField with only one dimension field
  186. to make sure the dimension update is correctly run on concrete subclass
  187. instance post-initialization.
  188. """
  189. mugshot = TestImageField(storage=temp_storage, upload_to='tests',
  190. height_field='mugshot_height')
  191. mugshot_height = models.PositiveSmallIntegerField()
  192. class Meta:
  193. abstract = True
  194. class PersonWithHeight(AbstractPersonWithHeight):
  195. """
  196. Concrete model that subclass an abstract one with only on dimension
  197. field.
  198. """
  199. name = models.CharField(max_length=50)
  200. class PersonWithHeightAndWidth(models.Model):
  201. """
  202. Model that defines height and width fields after the ImageField.
  203. """
  204. name = models.CharField(max_length=50)
  205. mugshot = TestImageField(storage=temp_storage, upload_to='tests',
  206. height_field='mugshot_height',
  207. width_field='mugshot_width')
  208. mugshot_height = models.PositiveSmallIntegerField()
  209. mugshot_width = models.PositiveSmallIntegerField()
  210. class PersonDimensionsFirst(models.Model):
  211. """
  212. Model that defines height and width fields before the ImageField.
  213. """
  214. name = models.CharField(max_length=50)
  215. mugshot_height = models.PositiveSmallIntegerField()
  216. mugshot_width = models.PositiveSmallIntegerField()
  217. mugshot = TestImageField(storage=temp_storage, upload_to='tests',
  218. height_field='mugshot_height',
  219. width_field='mugshot_width')
  220. class PersonTwoImages(models.Model):
  221. """
  222. Model that:
  223. * Defines two ImageFields
  224. * Defines the height/width fields before the ImageFields
  225. * Has a nullable ImageField
  226. """
  227. name = models.CharField(max_length=50)
  228. mugshot_height = models.PositiveSmallIntegerField()
  229. mugshot_width = models.PositiveSmallIntegerField()
  230. mugshot = TestImageField(storage=temp_storage, upload_to='tests',
  231. height_field='mugshot_height',
  232. width_field='mugshot_width')
  233. headshot_height = models.PositiveSmallIntegerField(
  234. blank=True, null=True)
  235. headshot_width = models.PositiveSmallIntegerField(
  236. blank=True, null=True)
  237. headshot = TestImageField(blank=True, null=True,
  238. storage=temp_storage, upload_to='tests',
  239. height_field='headshot_height',
  240. width_field='headshot_width')
  241. class CustomJSONDecoder(json.JSONDecoder):
  242. def __init__(self, object_hook=None, *args, **kwargs):
  243. return super().__init__(object_hook=self.as_uuid, *args, **kwargs)
  244. def as_uuid(self, dct):
  245. if 'uuid' in dct:
  246. dct['uuid'] = uuid.UUID(dct['uuid'])
  247. return dct
  248. class JSONModel(models.Model):
  249. value = models.JSONField()
  250. class Meta:
  251. required_db_features = {'supports_json_field'}
  252. class NullableJSONModel(models.Model):
  253. value = models.JSONField(blank=True, null=True)
  254. value_custom = models.JSONField(
  255. encoder=DjangoJSONEncoder,
  256. decoder=CustomJSONDecoder,
  257. null=True,
  258. )
  259. class Meta:
  260. required_db_features = {'supports_json_field'}
  261. class RelatedJSONModel(models.Model):
  262. value = models.JSONField()
  263. json_model = models.ForeignKey(NullableJSONModel, models.CASCADE)
  264. class Meta:
  265. required_db_features = {'supports_json_field'}
  266. class AllFieldsModel(models.Model):
  267. big_integer = models.BigIntegerField()
  268. binary = models.BinaryField()
  269. boolean = models.BooleanField(default=False)
  270. char = models.CharField(max_length=10)
  271. date = models.DateField()
  272. datetime = models.DateTimeField()
  273. decimal = models.DecimalField(decimal_places=2, max_digits=2)
  274. duration = models.DurationField()
  275. email = models.EmailField()
  276. file_path = models.FilePathField()
  277. floatf = models.FloatField()
  278. integer = models.IntegerField()
  279. generic_ip = models.GenericIPAddressField()
  280. null_boolean = models.NullBooleanField()
  281. positive_integer = models.PositiveIntegerField()
  282. positive_small_integer = models.PositiveSmallIntegerField()
  283. slug = models.SlugField()
  284. small_integer = models.SmallIntegerField()
  285. text = models.TextField()
  286. time = models.TimeField()
  287. url = models.URLField()
  288. uuid = models.UUIDField()
  289. fo = models.ForeignObject(
  290. 'self',
  291. on_delete=models.CASCADE,
  292. from_fields=['positive_integer'],
  293. to_fields=['id'],
  294. related_name='reverse'
  295. )
  296. fk = models.ForeignKey(
  297. 'self',
  298. models.CASCADE,
  299. related_name='reverse2'
  300. )
  301. m2m = models.ManyToManyField('self')
  302. oto = models.OneToOneField('self', models.CASCADE)
  303. object_id = models.PositiveIntegerField()
  304. content_type = models.ForeignKey(ContentType, models.CASCADE)
  305. gfk = GenericForeignKey()
  306. gr = GenericRelation(DataModel)
  307. class ManyToMany(models.Model):
  308. m2m = models.ManyToManyField('self')
  309. ###############################################################################
  310. class UUIDModel(models.Model):
  311. field = models.UUIDField()
  312. class NullableUUIDModel(models.Model):
  313. field = models.UUIDField(blank=True, null=True)
  314. class PrimaryKeyUUIDModel(models.Model):
  315. id = models.UUIDField(primary_key=True, default=uuid.uuid4)
  316. class RelatedToUUIDModel(models.Model):
  317. uuid_fk = models.ForeignKey('PrimaryKeyUUIDModel', models.CASCADE)
  318. class UUIDChild(PrimaryKeyUUIDModel):
  319. pass
  320. class UUIDGrandchild(UUIDChild):
  321. pass