models.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. import datetime
  2. import os
  3. import tempfile
  4. import uuid
  5. from django.core import validators
  6. from django.core.exceptions import ValidationError
  7. from django.core.files.storage import FileSystemStorage
  8. from django.db import models
  9. temp_storage_dir = tempfile.mkdtemp()
  10. temp_storage = FileSystemStorage(temp_storage_dir)
  11. class Person(models.Model):
  12. name = models.CharField(max_length=100)
  13. class Category(models.Model):
  14. name = models.CharField(max_length=20)
  15. slug = models.SlugField(max_length=20)
  16. url = models.CharField("The URL", max_length=40)
  17. class Meta:
  18. ordering = ("pk",)
  19. def __str__(self):
  20. return self.name
  21. def __repr__(self):
  22. return self.__str__()
  23. class WriterManager(models.Manager):
  24. def get_queryset(self):
  25. qs = super().get_queryset()
  26. return qs.filter(archived=False)
  27. class Writer(models.Model):
  28. name = models.CharField(max_length=50, help_text="Use both first and last names.")
  29. archived = models.BooleanField(default=False, editable=False)
  30. objects = WriterManager()
  31. class Meta:
  32. ordering = ("name",)
  33. def __str__(self):
  34. return self.name
  35. class Article(models.Model):
  36. ARTICLE_STATUS = (
  37. (1, "Draft"),
  38. (2, "Pending"),
  39. (3, "Live"),
  40. )
  41. headline = models.CharField(max_length=50)
  42. slug = models.SlugField()
  43. pub_date = models.DateField()
  44. created = models.DateField(editable=False)
  45. writer = models.ForeignKey(Writer, models.CASCADE)
  46. article = models.TextField()
  47. categories = models.ManyToManyField(Category, blank=True)
  48. status = models.PositiveIntegerField(choices=ARTICLE_STATUS, blank=True, null=True)
  49. def save(self, *args, **kwargs):
  50. if not self.id:
  51. self.created = datetime.date.today()
  52. return super().save(*args, **kwargs)
  53. def __str__(self):
  54. return self.headline
  55. class ImprovedArticle(models.Model):
  56. article = models.OneToOneField(Article, models.CASCADE)
  57. class ImprovedArticleWithParentLink(models.Model):
  58. article = models.OneToOneField(Article, models.CASCADE, parent_link=True)
  59. class BetterWriter(Writer):
  60. score = models.IntegerField()
  61. class Publication(models.Model):
  62. title = models.CharField(max_length=30)
  63. date_published = models.DateField()
  64. def __str__(self):
  65. return self.title
  66. def default_mode():
  67. return "di"
  68. def default_category():
  69. return 3
  70. class PublicationDefaults(models.Model):
  71. MODE_CHOICES = (("di", "direct"), ("de", "delayed"))
  72. CATEGORY_CHOICES = ((1, "Games"), (2, "Comics"), (3, "Novel"))
  73. title = models.CharField(max_length=30)
  74. date_published = models.DateField(default=datetime.date.today)
  75. datetime_published = models.DateTimeField(default=datetime.datetime(2000, 1, 1))
  76. mode = models.CharField(max_length=2, choices=MODE_CHOICES, default=default_mode)
  77. category = models.IntegerField(choices=CATEGORY_CHOICES, default=default_category)
  78. active = models.BooleanField(default=True)
  79. file = models.FileField(default="default.txt")
  80. class Author(models.Model):
  81. publication = models.OneToOneField(
  82. Publication, models.SET_NULL, null=True, blank=True
  83. )
  84. full_name = models.CharField(max_length=255)
  85. class Author1(models.Model):
  86. publication = models.OneToOneField(Publication, models.CASCADE, null=False)
  87. full_name = models.CharField(max_length=255)
  88. class WriterProfile(models.Model):
  89. writer = models.OneToOneField(Writer, models.CASCADE, primary_key=True)
  90. age = models.PositiveIntegerField()
  91. def __str__(self):
  92. return "%s is %s" % (self.writer, self.age)
  93. class Document(models.Model):
  94. myfile = models.FileField(upload_to="unused", blank=True)
  95. class TextFile(models.Model):
  96. description = models.CharField(max_length=20)
  97. file = models.FileField(storage=temp_storage, upload_to="tests", max_length=15)
  98. def __str__(self):
  99. return self.description
  100. class CustomFileField(models.FileField):
  101. def save_form_data(self, instance, data):
  102. been_here = getattr(self, "been_saved", False)
  103. assert not been_here, "save_form_data called more than once"
  104. setattr(self, "been_saved", True)
  105. class CustomFF(models.Model):
  106. f = CustomFileField(upload_to="unused", blank=True)
  107. class FilePathModel(models.Model):
  108. path = models.FilePathField(
  109. path=os.path.dirname(__file__), match="models.py", blank=True
  110. )
  111. try:
  112. from PIL import Image # NOQA: detect if Pillow is installed
  113. test_images = True
  114. class ImageFile(models.Model):
  115. def custom_upload_path(self, filename):
  116. path = self.path or "tests"
  117. return "%s/%s" % (path, filename)
  118. description = models.CharField(max_length=20)
  119. # Deliberately put the image field *after* the width/height fields to
  120. # trigger the bug in #10404 with width/height not getting assigned.
  121. width = models.IntegerField(editable=False)
  122. height = models.IntegerField(editable=False)
  123. image = models.ImageField(
  124. storage=temp_storage,
  125. upload_to=custom_upload_path,
  126. width_field="width",
  127. height_field="height",
  128. )
  129. path = models.CharField(max_length=16, blank=True, default="")
  130. def __str__(self):
  131. return self.description
  132. class OptionalImageFile(models.Model):
  133. def custom_upload_path(self, filename):
  134. path = self.path or "tests"
  135. return "%s/%s" % (path, filename)
  136. description = models.CharField(max_length=20)
  137. image = models.ImageField(
  138. storage=temp_storage,
  139. upload_to=custom_upload_path,
  140. width_field="width",
  141. height_field="height",
  142. blank=True,
  143. null=True,
  144. )
  145. width = models.IntegerField(editable=False, null=True)
  146. height = models.IntegerField(editable=False, null=True)
  147. path = models.CharField(max_length=16, blank=True, default="")
  148. def __str__(self):
  149. return self.description
  150. class NoExtensionImageFile(models.Model):
  151. def upload_to(self, filename):
  152. return "tests/no_extension"
  153. description = models.CharField(max_length=20)
  154. image = models.ImageField(storage=temp_storage, upload_to=upload_to)
  155. def __str__(self):
  156. return self.description
  157. except ImportError:
  158. test_images = False
  159. class Homepage(models.Model):
  160. url = models.URLField()
  161. class Product(models.Model):
  162. slug = models.SlugField(unique=True)
  163. def __str__(self):
  164. return self.slug
  165. class Price(models.Model):
  166. price = models.DecimalField(max_digits=10, decimal_places=2)
  167. quantity = models.PositiveIntegerField()
  168. class Meta:
  169. unique_together = (("price", "quantity"),)
  170. def __str__(self):
  171. return "%s for %s" % (self.quantity, self.price)
  172. class Triple(models.Model):
  173. left = models.IntegerField()
  174. middle = models.IntegerField()
  175. right = models.IntegerField()
  176. class Meta:
  177. unique_together = (("left", "middle"), ("middle", "right"))
  178. class ArticleStatus(models.Model):
  179. ARTICLE_STATUS_CHAR = (
  180. ("d", "Draft"),
  181. ("p", "Pending"),
  182. ("l", "Live"),
  183. )
  184. status = models.CharField(
  185. max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True
  186. )
  187. class Inventory(models.Model):
  188. barcode = models.PositiveIntegerField(unique=True)
  189. parent = models.ForeignKey(
  190. "self", models.SET_NULL, to_field="barcode", blank=True, null=True
  191. )
  192. name = models.CharField(blank=False, max_length=20)
  193. class Meta:
  194. ordering = ("name",)
  195. def __str__(self):
  196. return self.name
  197. def __repr__(self):
  198. return self.__str__()
  199. class Book(models.Model):
  200. title = models.CharField(max_length=40)
  201. author = models.ForeignKey(Writer, models.SET_NULL, blank=True, null=True)
  202. special_id = models.IntegerField(blank=True, null=True, unique=True)
  203. class Meta:
  204. unique_together = ("title", "author")
  205. class BookXtra(models.Model):
  206. isbn = models.CharField(max_length=16, unique=True)
  207. suffix1 = models.IntegerField(blank=True, default=0)
  208. suffix2 = models.IntegerField(blank=True, default=0)
  209. class Meta:
  210. unique_together = ("suffix1", "suffix2")
  211. abstract = True
  212. class DerivedBook(Book, BookXtra):
  213. pass
  214. class ExplicitPK(models.Model):
  215. key = models.CharField(max_length=20, primary_key=True)
  216. desc = models.CharField(max_length=20, blank=True, unique=True)
  217. class Meta:
  218. unique_together = ("key", "desc")
  219. def __str__(self):
  220. return self.key
  221. class Post(models.Model):
  222. title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
  223. slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
  224. subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
  225. posted = models.DateField()
  226. def __str__(self):
  227. return self.title
  228. class DateTimePost(models.Model):
  229. title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
  230. slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
  231. subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
  232. posted = models.DateTimeField(editable=False)
  233. def __str__(self):
  234. return self.title
  235. class DerivedPost(Post):
  236. pass
  237. class BigInt(models.Model):
  238. biggie = models.BigIntegerField()
  239. def __str__(self):
  240. return str(self.biggie)
  241. class MarkupField(models.CharField):
  242. def __init__(self, *args, **kwargs):
  243. kwargs["max_length"] = 20
  244. super().__init__(*args, **kwargs)
  245. def formfield(self, **kwargs):
  246. # don't allow this field to be used in form (real use-case might be
  247. # that you know the markup will always be X, but it is among an app
  248. # that allows the user to say it could be something else)
  249. # regressed at r10062
  250. return None
  251. class CustomFieldForExclusionModel(models.Model):
  252. name = models.CharField(max_length=10)
  253. markup = MarkupField()
  254. class FlexibleDatePost(models.Model):
  255. title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
  256. slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
  257. subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
  258. posted = models.DateField(blank=True, null=True)
  259. class Colour(models.Model):
  260. name = models.CharField(max_length=50)
  261. def __iter__(self):
  262. yield from range(5)
  263. def __str__(self):
  264. return self.name
  265. class ColourfulItem(models.Model):
  266. name = models.CharField(max_length=50)
  267. colours = models.ManyToManyField(Colour)
  268. class CustomErrorMessage(models.Model):
  269. name1 = models.CharField(
  270. max_length=50,
  271. validators=[validators.validate_slug],
  272. error_messages={"invalid": "Model custom error message."},
  273. )
  274. name2 = models.CharField(
  275. max_length=50,
  276. validators=[validators.validate_slug],
  277. error_messages={"invalid": "Model custom error message."},
  278. )
  279. def clean(self):
  280. if self.name1 == "FORBIDDEN_VALUE":
  281. raise ValidationError(
  282. {"name1": [ValidationError("Model.clean() error messages.")]}
  283. )
  284. elif self.name1 == "FORBIDDEN_VALUE2":
  285. raise ValidationError(
  286. {"name1": "Model.clean() error messages (simpler syntax)."}
  287. )
  288. elif self.name1 == "GLOBAL_ERROR":
  289. raise ValidationError("Global error message.")
  290. def today_callable_dict():
  291. return {"last_action__gte": datetime.datetime.today()}
  292. def today_callable_q():
  293. return models.Q(last_action__gte=datetime.datetime.today())
  294. class Character(models.Model):
  295. username = models.CharField(max_length=100)
  296. last_action = models.DateTimeField()
  297. def __str__(self):
  298. return self.username
  299. class StumpJoke(models.Model):
  300. most_recently_fooled = models.ForeignKey(
  301. Character,
  302. models.CASCADE,
  303. limit_choices_to=today_callable_dict,
  304. related_name="jokes",
  305. )
  306. has_fooled_today = models.ManyToManyField(
  307. Character,
  308. limit_choices_to=today_callable_q,
  309. related_name="jokes_today",
  310. )
  311. funny = models.BooleanField(default=False)
  312. # Model for #13776
  313. class Student(models.Model):
  314. character = models.ForeignKey(Character, models.CASCADE)
  315. study = models.CharField(max_length=30)
  316. # Model for #639
  317. class Photo(models.Model):
  318. title = models.CharField(max_length=30)
  319. image = models.FileField(storage=temp_storage, upload_to="tests")
  320. # Support code for the tests; this keeps track of how many times save()
  321. # gets called on each instance.
  322. def __init__(self, *args, **kwargs):
  323. super().__init__(*args, **kwargs)
  324. self._savecount = 0
  325. def save(self, force_insert=False, force_update=False):
  326. super().save(force_insert=force_insert, force_update=force_update)
  327. self._savecount += 1
  328. class UUIDPK(models.Model):
  329. uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  330. name = models.CharField(max_length=30)
  331. # Models for #24706
  332. class StrictAssignmentFieldSpecific(models.Model):
  333. title = models.CharField(max_length=30)
  334. _should_error = False
  335. def __setattr__(self, key, value):
  336. if self._should_error is True:
  337. raise ValidationError(message={key: "Cannot set attribute"}, code="invalid")
  338. super().__setattr__(key, value)
  339. class StrictAssignmentAll(models.Model):
  340. title = models.CharField(max_length=30)
  341. _should_error = False
  342. def __setattr__(self, key, value):
  343. if self._should_error is True:
  344. raise ValidationError(message="Cannot set attribute", code="invalid")
  345. super().__setattr__(key, value)
  346. # A model with ForeignKey(blank=False, null=True)
  347. class Award(models.Model):
  348. name = models.CharField(max_length=30)
  349. character = models.ForeignKey(Character, models.SET_NULL, blank=False, null=True)
  350. class NullableUniqueCharFieldModel(models.Model):
  351. codename = models.CharField(max_length=50, blank=True, null=True, unique=True)
  352. email = models.EmailField(blank=True, null=True)
  353. slug = models.SlugField(blank=True, null=True)
  354. url = models.URLField(blank=True, null=True)
  355. class Number(models.Model):
  356. value = models.IntegerField()
  357. class NumbersToDice(models.Model):
  358. number = models.ForeignKey("Number", on_delete=models.CASCADE)
  359. die = models.ForeignKey("Dice", on_delete=models.CASCADE)
  360. class Dice(models.Model):
  361. numbers = models.ManyToManyField(
  362. Number,
  363. through=NumbersToDice,
  364. limit_choices_to=models.Q(value__gte=1),
  365. )