mirror of
				https://github.com/django/django.git
				synced 2025-10-29 08:36:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			546 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			546 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import datetime
 | |
| import os
 | |
| import tempfile
 | |
| import uuid
 | |
| 
 | |
| from django.core import validators
 | |
| from django.core.exceptions import ValidationError
 | |
| from django.core.files.storage import FileSystemStorage
 | |
| from django.db import models
 | |
| 
 | |
| temp_storage_dir = tempfile.mkdtemp()
 | |
| temp_storage = FileSystemStorage(temp_storage_dir)
 | |
| 
 | |
| 
 | |
| class Person(models.Model):
 | |
|     name = models.CharField(max_length=100)
 | |
| 
 | |
| 
 | |
| class Category(models.Model):
 | |
|     name = models.CharField(max_length=20)
 | |
|     slug = models.SlugField(max_length=20)
 | |
|     url = models.CharField("The URL", max_length=40)
 | |
| 
 | |
|     class Meta:
 | |
|         ordering = ("pk",)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return self.__str__()
 | |
| 
 | |
| 
 | |
| class WriterManager(models.Manager):
 | |
|     def get_queryset(self):
 | |
|         qs = super().get_queryset()
 | |
|         return qs.filter(archived=False)
 | |
| 
 | |
| 
 | |
| class Writer(models.Model):
 | |
|     name = models.CharField(max_length=50, help_text="Use both first and last names.")
 | |
|     archived = models.BooleanField(default=False, editable=False)
 | |
| 
 | |
|     objects = WriterManager()
 | |
| 
 | |
|     class Meta:
 | |
|         ordering = ("name",)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name
 | |
| 
 | |
| 
 | |
| class Article(models.Model):
 | |
|     ARTICLE_STATUS = (
 | |
|         (1, "Draft"),
 | |
|         (2, "Pending"),
 | |
|         (3, "Live"),
 | |
|     )
 | |
|     headline = models.CharField(max_length=50)
 | |
|     slug = models.SlugField()
 | |
|     pub_date = models.DateField()
 | |
|     created = models.DateField(editable=False)
 | |
|     writer = models.ForeignKey(Writer, models.CASCADE)
 | |
|     article = models.TextField()
 | |
|     categories = models.ManyToManyField(Category, blank=True)
 | |
|     status = models.PositiveIntegerField(choices=ARTICLE_STATUS, blank=True, null=True)
 | |
| 
 | |
|     def save(self, *args, **kwargs):
 | |
|         if not self.id:
 | |
|             self.created = datetime.date.today()
 | |
|         return super().save(*args, **kwargs)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.headline
 | |
| 
 | |
| 
 | |
| class ImprovedArticle(models.Model):
 | |
|     article = models.OneToOneField(Article, models.CASCADE)
 | |
| 
 | |
| 
 | |
| class ImprovedArticleWithParentLink(models.Model):
 | |
|     article = models.OneToOneField(Article, models.CASCADE, parent_link=True)
 | |
| 
 | |
| 
 | |
| class BetterWriter(Writer):
 | |
|     score = models.IntegerField()
 | |
| 
 | |
| 
 | |
| class Publication(models.Model):
 | |
|     title = models.CharField(max_length=30)
 | |
|     date_published = models.DateField()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.title
 | |
| 
 | |
| 
 | |
| def default_mode():
 | |
|     return "di"
 | |
| 
 | |
| 
 | |
| def default_category():
 | |
|     return 3
 | |
| 
 | |
| 
 | |
| class PublicationDefaults(models.Model):
 | |
|     MODE_CHOICES = (("di", "direct"), ("de", "delayed"))
 | |
|     CATEGORY_CHOICES = ((1, "Games"), (2, "Comics"), (3, "Novel"))
 | |
|     title = models.CharField(max_length=30)
 | |
|     date_published = models.DateField(default=datetime.date.today)
 | |
|     datetime_published = models.DateTimeField(default=datetime.datetime(2000, 1, 1))
 | |
|     mode = models.CharField(max_length=2, choices=MODE_CHOICES, default=default_mode)
 | |
|     category = models.IntegerField(choices=CATEGORY_CHOICES, default=default_category)
 | |
|     active = models.BooleanField(default=True)
 | |
|     file = models.FileField(default="default.txt")
 | |
| 
 | |
| 
 | |
| class Author(models.Model):
 | |
|     publication = models.OneToOneField(
 | |
|         Publication, models.SET_NULL, null=True, blank=True
 | |
|     )
 | |
|     full_name = models.CharField(max_length=255)
 | |
| 
 | |
| 
 | |
| class Author1(models.Model):
 | |
|     publication = models.OneToOneField(Publication, models.CASCADE, null=False)
 | |
|     full_name = models.CharField(max_length=255)
 | |
| 
 | |
| 
 | |
| class WriterProfile(models.Model):
 | |
|     writer = models.OneToOneField(Writer, models.CASCADE, primary_key=True)
 | |
|     age = models.PositiveIntegerField()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return "%s is %s" % (self.writer, self.age)
 | |
| 
 | |
| 
 | |
| class Document(models.Model):
 | |
|     myfile = models.FileField(storage=temp_storage, upload_to="unused", blank=True)
 | |
| 
 | |
| 
 | |
| class TextFile(models.Model):
 | |
|     description = models.CharField(max_length=20)
 | |
|     file = models.FileField(storage=temp_storage, upload_to="tests", max_length=15)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.description
 | |
| 
 | |
| 
 | |
| class CustomFileField(models.FileField):
 | |
|     def save_form_data(self, instance, data):
 | |
|         been_here = getattr(self, "been_saved", False)
 | |
|         assert not been_here, "save_form_data called more than once"
 | |
|         setattr(self, "been_saved", True)
 | |
| 
 | |
| 
 | |
| class CustomFF(models.Model):
 | |
|     f = CustomFileField(upload_to="unused", blank=True)
 | |
| 
 | |
| 
 | |
| class FilePathModel(models.Model):
 | |
|     path = models.FilePathField(
 | |
|         path=os.path.dirname(__file__), match="models.py", blank=True
 | |
|     )
 | |
| 
 | |
| 
 | |
| try:
 | |
|     from PIL import Image  # NOQA: detect if Pillow is installed
 | |
| 
 | |
|     test_images = True
 | |
| 
 | |
|     class ImageFile(models.Model):
 | |
|         def custom_upload_path(self, filename):
 | |
|             path = self.path or "tests"
 | |
|             return "%s/%s" % (path, filename)
 | |
| 
 | |
|         description = models.CharField(max_length=20)
 | |
| 
 | |
|         # Deliberately put the image field *after* the width/height fields to
 | |
|         # trigger the bug in #10404 with width/height not getting assigned.
 | |
|         width = models.IntegerField(editable=False)
 | |
|         height = models.IntegerField(editable=False)
 | |
|         image = models.ImageField(
 | |
|             storage=temp_storage,
 | |
|             upload_to=custom_upload_path,
 | |
|             width_field="width",
 | |
|             height_field="height",
 | |
|         )
 | |
|         path = models.CharField(max_length=16, blank=True, default="")
 | |
| 
 | |
|         def __str__(self):
 | |
|             return self.description
 | |
| 
 | |
|     class OptionalImageFile(models.Model):
 | |
|         def custom_upload_path(self, filename):
 | |
|             path = self.path or "tests"
 | |
|             return "%s/%s" % (path, filename)
 | |
| 
 | |
|         description = models.CharField(max_length=20)
 | |
|         image = models.ImageField(
 | |
|             storage=temp_storage,
 | |
|             upload_to=custom_upload_path,
 | |
|             width_field="width",
 | |
|             height_field="height",
 | |
|             blank=True,
 | |
|             null=True,
 | |
|         )
 | |
|         width = models.IntegerField(editable=False, null=True)
 | |
|         height = models.IntegerField(editable=False, null=True)
 | |
|         path = models.CharField(max_length=16, blank=True, default="")
 | |
| 
 | |
|         def __str__(self):
 | |
|             return self.description
 | |
| 
 | |
|     class NoExtensionImageFile(models.Model):
 | |
|         def upload_to(self, filename):
 | |
|             return "tests/no_extension"
 | |
| 
 | |
|         description = models.CharField(max_length=20)
 | |
|         image = models.ImageField(storage=temp_storage, upload_to=upload_to)
 | |
| 
 | |
|         def __str__(self):
 | |
|             return self.description
 | |
| 
 | |
| except ImportError:
 | |
|     test_images = False
 | |
| 
 | |
| 
 | |
| class Homepage(models.Model):
 | |
|     url = models.URLField()
 | |
| 
 | |
| 
 | |
| class Product(models.Model):
 | |
|     slug = models.SlugField(unique=True)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.slug
 | |
| 
 | |
| 
 | |
| class Price(models.Model):
 | |
|     price = models.DecimalField(max_digits=10, decimal_places=2)
 | |
|     quantity = models.PositiveIntegerField()
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = (("price", "quantity"),)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return "%s for %s" % (self.quantity, self.price)
 | |
| 
 | |
| 
 | |
| class Triple(models.Model):
 | |
|     left = models.IntegerField()
 | |
|     middle = models.IntegerField()
 | |
|     right = models.IntegerField()
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = (("left", "middle"), ("middle", "right"))
 | |
| 
 | |
| 
 | |
| class ArticleStatus(models.Model):
 | |
|     ARTICLE_STATUS_CHAR = (
 | |
|         ("d", "Draft"),
 | |
|         ("p", "Pending"),
 | |
|         ("l", "Live"),
 | |
|     )
 | |
|     status = models.CharField(
 | |
|         max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True
 | |
|     )
 | |
| 
 | |
| 
 | |
| class Inventory(models.Model):
 | |
|     barcode = models.PositiveIntegerField(unique=True)
 | |
|     parent = models.ForeignKey(
 | |
|         "self", models.SET_NULL, to_field="barcode", blank=True, null=True
 | |
|     )
 | |
|     name = models.CharField(blank=False, max_length=20)
 | |
| 
 | |
|     class Meta:
 | |
|         ordering = ("name",)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return self.__str__()
 | |
| 
 | |
| 
 | |
| class Book(models.Model):
 | |
|     title = models.CharField(max_length=40)
 | |
|     author = models.ForeignKey(Writer, models.SET_NULL, blank=True, null=True)
 | |
|     special_id = models.IntegerField(blank=True, null=True, unique=True)
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = ("title", "author")
 | |
| 
 | |
| 
 | |
| class BookXtra(models.Model):
 | |
|     isbn = models.CharField(max_length=16, unique=True)
 | |
|     suffix1 = models.IntegerField(blank=True, default=0)
 | |
|     suffix2 = models.IntegerField(blank=True, default=0)
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = ("suffix1", "suffix2")
 | |
|         abstract = True
 | |
| 
 | |
| 
 | |
| class DerivedBook(Book, BookXtra):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class ExplicitPK(models.Model):
 | |
|     key = models.CharField(max_length=20, primary_key=True)
 | |
|     desc = models.CharField(max_length=20, blank=True, unique=True)
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = ("key", "desc")
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.key
 | |
| 
 | |
| 
 | |
| class Post(models.Model):
 | |
|     title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
 | |
|     slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
 | |
|     subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
 | |
|     posted = models.DateField()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.title
 | |
| 
 | |
| 
 | |
| class DateTimePost(models.Model):
 | |
|     title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
 | |
|     slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
 | |
|     subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
 | |
|     posted = models.DateTimeField(editable=False)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.title
 | |
| 
 | |
| 
 | |
| class DerivedPost(Post):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class BigInt(models.Model):
 | |
|     biggie = models.BigIntegerField()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return str(self.biggie)
 | |
| 
 | |
| 
 | |
| class MarkupField(models.CharField):
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         kwargs["max_length"] = 20
 | |
|         super().__init__(*args, **kwargs)
 | |
| 
 | |
|     def formfield(self, **kwargs):
 | |
|         # don't allow this field to be used in form (real use-case might be
 | |
|         # that you know the markup will always be X, but it is among an app
 | |
|         # that allows the user to say it could be something else)
 | |
|         # regressed at r10062
 | |
|         return None
 | |
| 
 | |
| 
 | |
| class CustomFieldForExclusionModel(models.Model):
 | |
|     name = models.CharField(max_length=10)
 | |
|     markup = MarkupField()
 | |
| 
 | |
| 
 | |
| class FlexibleDatePost(models.Model):
 | |
|     title = models.CharField(max_length=50, unique_for_date="posted", blank=True)
 | |
|     slug = models.CharField(max_length=50, unique_for_year="posted", blank=True)
 | |
|     subtitle = models.CharField(max_length=50, unique_for_month="posted", blank=True)
 | |
|     posted = models.DateField(blank=True, null=True)
 | |
| 
 | |
| 
 | |
| class Color(models.Model):
 | |
|     name = models.CharField(max_length=50)
 | |
| 
 | |
|     def __iter__(self):
 | |
|         yield from range(5)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name
 | |
| 
 | |
| 
 | |
| class ColorfulItem(models.Model):
 | |
|     name = models.CharField(max_length=50)
 | |
|     colors = models.ManyToManyField(Color)
 | |
| 
 | |
| 
 | |
| class CustomErrorMessage(models.Model):
 | |
|     name1 = models.CharField(
 | |
|         max_length=50,
 | |
|         validators=[validators.validate_slug],
 | |
|         error_messages={"invalid": "Model custom error message."},
 | |
|     )
 | |
|     name2 = models.CharField(
 | |
|         max_length=50,
 | |
|         validators=[validators.validate_slug],
 | |
|         error_messages={"invalid": "Model custom error message."},
 | |
|     )
 | |
| 
 | |
|     def clean(self):
 | |
|         if self.name1 == "FORBIDDEN_VALUE":
 | |
|             raise ValidationError(
 | |
|                 {"name1": [ValidationError("Model.clean() error messages.")]}
 | |
|             )
 | |
|         elif self.name1 == "FORBIDDEN_VALUE2":
 | |
|             raise ValidationError(
 | |
|                 {"name1": "Model.clean() error messages (simpler syntax)."}
 | |
|             )
 | |
|         elif self.name1 == "GLOBAL_ERROR":
 | |
|             raise ValidationError("Global error message.")
 | |
| 
 | |
| 
 | |
| def today_callable_dict():
 | |
|     return {"last_action__gte": datetime.datetime.today()}
 | |
| 
 | |
| 
 | |
| def today_callable_q():
 | |
|     return models.Q(last_action__gte=datetime.datetime.today())
 | |
| 
 | |
| 
 | |
| class Character(models.Model):
 | |
|     username = models.CharField(max_length=100)
 | |
|     last_action = models.DateTimeField()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.username
 | |
| 
 | |
| 
 | |
| class StumpJoke(models.Model):
 | |
|     most_recently_fooled = models.ForeignKey(
 | |
|         Character,
 | |
|         models.CASCADE,
 | |
|         limit_choices_to=today_callable_dict,
 | |
|         related_name="jokes",
 | |
|     )
 | |
|     has_fooled_today = models.ManyToManyField(
 | |
|         Character,
 | |
|         limit_choices_to=today_callable_q,
 | |
|         related_name="jokes_today",
 | |
|     )
 | |
|     funny = models.BooleanField(default=False)
 | |
| 
 | |
| 
 | |
| # Model for #13776
 | |
| class Student(models.Model):
 | |
|     character = models.ForeignKey(Character, models.CASCADE)
 | |
|     study = models.CharField(max_length=30)
 | |
| 
 | |
| 
 | |
| # Model for #639
 | |
| class Photo(models.Model):
 | |
|     title = models.CharField(max_length=30)
 | |
|     image = models.FileField(storage=temp_storage, upload_to="tests")
 | |
| 
 | |
|     # Support code for the tests; this keeps track of how many times save()
 | |
|     # gets called on each instance.
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         self._savecount = 0
 | |
| 
 | |
|     def save(self, force_insert=False, force_update=False):
 | |
|         super().save(force_insert=force_insert, force_update=force_update)
 | |
|         self._savecount += 1
 | |
| 
 | |
| 
 | |
| class UUIDPK(models.Model):
 | |
|     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
 | |
|     name = models.CharField(max_length=30)
 | |
| 
 | |
| 
 | |
| # Models for #24706
 | |
| class StrictAssignmentFieldSpecific(models.Model):
 | |
|     title = models.CharField(max_length=30)
 | |
|     _should_error = False
 | |
| 
 | |
|     def __setattr__(self, key, value):
 | |
|         if self._should_error is True:
 | |
|             raise ValidationError(message={key: "Cannot set attribute"}, code="invalid")
 | |
|         super().__setattr__(key, value)
 | |
| 
 | |
| 
 | |
| class StrictAssignmentAll(models.Model):
 | |
|     title = models.CharField(max_length=30)
 | |
|     _should_error = False
 | |
| 
 | |
|     def __setattr__(self, key, value):
 | |
|         if self._should_error is True:
 | |
|             raise ValidationError(message="Cannot set attribute", code="invalid")
 | |
|         super().__setattr__(key, value)
 | |
| 
 | |
| 
 | |
| # A model with ForeignKey(blank=False, null=True)
 | |
| class Award(models.Model):
 | |
|     name = models.CharField(max_length=30)
 | |
|     character = models.ForeignKey(Character, models.SET_NULL, blank=False, null=True)
 | |
| 
 | |
| 
 | |
| class NullableUniqueCharFieldModel(models.Model):
 | |
|     codename = models.CharField(max_length=50, blank=True, null=True, unique=True)
 | |
|     email = models.EmailField(blank=True, null=True)
 | |
|     slug = models.SlugField(blank=True, null=True)
 | |
|     url = models.URLField(blank=True, null=True)
 | |
| 
 | |
| 
 | |
| class Number(models.Model):
 | |
|     value = models.IntegerField()
 | |
| 
 | |
| 
 | |
| class NumbersToDice(models.Model):
 | |
|     number = models.ForeignKey("Number", on_delete=models.CASCADE)
 | |
|     die = models.ForeignKey("Dice", on_delete=models.CASCADE)
 | |
| 
 | |
| 
 | |
| class Dice(models.Model):
 | |
|     numbers = models.ManyToManyField(
 | |
|         Number,
 | |
|         through=NumbersToDice,
 | |
|         limit_choices_to=models.Q(value__gte=1),
 | |
|     )
 | |
| 
 | |
| 
 | |
| class ConstraintsModel(models.Model):
 | |
|     name = models.CharField(max_length=100)
 | |
|     category = models.CharField(max_length=50, default="uncategorized")
 | |
|     price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
 | |
| 
 | |
|     class Meta:
 | |
|         required_db_features = {"supports_table_check_constraints"}
 | |
|         constraints = [
 | |
|             models.UniqueConstraint(
 | |
|                 "name",
 | |
|                 "category",
 | |
|                 name="unique_name_category",
 | |
|                 violation_error_message="This product already exists.",
 | |
|             ),
 | |
|             models.CheckConstraint(
 | |
|                 condition=models.Q(price__gt=0),
 | |
|                 name="price_gte_zero",
 | |
|                 violation_error_message="Price must be greater than zero.",
 | |
|             ),
 | |
|         ]
 |