contrived way of adding choices later model with fks to models with null booleanfield s 15040 bf models foreignkeybooleanmodel models cascade nbf models foreignkeynullbooleanmodel models cascade class fktocharmodels model don t want to depend on pillow in this test fieldimage models imagefieldverbose field these models aren t used in any test just here to ensure they validate successfully see ticket 16570 see ticket 18389 filefield imagefield if pillow available do these tests custom field file class that records whether or not the underlying file was opened set up a temp directory for file storage model that defines an imagefield with no dimension fields abstract model that defines an imagefield with only one dimension field to make sure the dimension update is correctly run on concrete subclass instance postinitialization concrete model that subclass an abstract one with only on dimension field model that defines height and width fields after the imagefield model that defines height and width fields before the imagefield model that defines two imagefields defines the heightwidth fields before the imagefields has a nullable imagefield contrived way of adding choices later model with fks to models with null booleanfield s 15040 model with fk to a model with a charfield primary key 19299 don t want to depend on pillow in this test field_image models imagefield verbose field these models aren t used in any test just here to ensure they validate successfully see ticket 16570 see ticket 18389 filefield imagefield if pillow available do these tests custom field file class that records whether or not the underlying file was opened set up a temp directory for file storage model that defines an imagefield with no dimension fields abstract model that defines an imagefield with only one dimension field to make sure the dimension update is correctly run on concrete subclass instance post initialization concrete model that subclass an abstract one with only on dimension field model that defines height and width fields after the imagefield model that defines height and width fields before the imagefield model that defines two imagefields defines the height width fields before the imagefields has a nullable imagefield
import json
import tempfile
import uuid

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.files.storage import FileSystemStorage
from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection, models
from django.db.models import F, Value
from django.db.models.fields.files import ImageFieldFile
from django.db.models.functions import Lower
from django.utils.functional import SimpleLazyObject
from django.utils.translation import gettext_lazy as _

try:
    from PIL import Image
except ImportError:
    Image = None


test_collation = SimpleLazyObject(
    lambda: connection.features.test_collations["virtual"]
)


class Foo(models.Model):
    a = models.CharField(max_length=10)
    d = models.DecimalField(max_digits=5, decimal_places=3)


def get_foo():
    return Foo.objects.get(id=1).pk


class Bar(models.Model):
    b = models.CharField(max_length=10)
    a = models.ForeignKey(Foo, models.CASCADE, default=get_foo, related_name="bars")


class Whiz(models.Model):
    CHOICES = {
        "Group 1": {
            1: "First",
            2: "Second",
        },
        "Group 2": (
            (3, "Third"),
            (4, "Fourth"),
        ),
        0: "Other",
        5: _("translated"),
    }
    c = models.IntegerField(choices=CHOICES, null=True)


class WhizDelayed(models.Model):
    c = models.IntegerField(choices=(), null=True)



WhizDelayed._meta.get_field("c").choices = Whiz.CHOICES


class WhizIter(models.Model):
    c = models.IntegerField(choices=iter(Whiz.CHOICES.items()), null=True)


class WhizIterEmpty(models.Model):
    c = models.CharField(choices=iter(()), blank=True, max_length=1)


class Choiceful(models.Model):
    class Suit(models.IntegerChoices):
        DIAMOND = 1, "Diamond"
        SPADE = 2, "Spade"
        HEART = 3, "Heart"
        CLUB = 4, "Club"

    def get_choices():
        return [(i, str(i)) for i in range(3)]

    no_choices = models.IntegerField(null=True)
    empty_choices = models.IntegerField(choices=(), null=True)
    with_choices = models.IntegerField(choices=[(1, "A")], null=True)
    with_choices_dict = models.IntegerField(choices={1: "A"}, null=True)
    with_choices_nested_dict = models.IntegerField(
        choices={"Thing": {1: "A"}}, null=True
    )
    empty_choices_bool = models.BooleanField(choices=())
    empty_choices_text = models.TextField(choices=())
    choices_from_enum = models.IntegerField(choices=Suit)
    choices_from_iterator = models.IntegerField(choices=((i, str(i)) for i in range(3)))
    choices_from_callable = models.IntegerField(choices=get_choices)


class BigD(models.Model):
    d = models.DecimalField(max_digits=32, decimal_places=30)


class FloatModel(models.Model):
    size = models.FloatField()


class BigS(models.Model):
    s = models.SlugField(max_length=255)


class UnicodeSlugField(models.Model):
    s = models.SlugField(max_length=255, allow_unicode=True)


class AutoModel(models.Model):
    value = models.AutoField(primary_key=True)


class BigAutoModel(models.Model):
    value = models.BigAutoField(primary_key=True)


class SmallAutoModel(models.Model):
    value = models.SmallAutoField(primary_key=True)


class SmallIntegerModel(models.Model):
    value = models.SmallIntegerField()


class IntegerModel(models.Model):
    value = models.IntegerField()


class BigIntegerModel(models.Model):
    value = models.BigIntegerField()
    null_value = models.BigIntegerField(null=True, blank=True)


class PositiveBigIntegerModel(models.Model):
    value = models.PositiveBigIntegerField()


class PositiveSmallIntegerModel(models.Model):
    value = models.PositiveSmallIntegerField()


class PositiveIntegerModel(models.Model):
    value = models.PositiveIntegerField()


class Post(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()


class NullBooleanModel(models.Model):
    nbfield = models.BooleanField(null=True, blank=True)


class BooleanModel(models.Model):
    bfield = models.BooleanField()


class DateTimeModel(models.Model):
    d = models.DateField()
    dt = models.DateTimeField()
    t = models.TimeField()


class DurationModel(models.Model):
    field = models.DurationField()


class NullDurationModel(models.Model):
    field = models.DurationField(null=True)


class PrimaryKeyCharModel(models.Model):
    string = models.CharField(max_length=10, primary_key=True)


class FksToBooleans(models.Model):
    

    bf = models.ForeignKey(BooleanModel, models.CASCADE)
    nbf = models.ForeignKey(NullBooleanModel, models.CASCADE)


class FkToChar(models.Model):
    

    out = models.ForeignKey(PrimaryKeyCharModel, models.CASCADE)


class RenamedField(models.Model):
    modelname = models.IntegerField(name="fieldname", choices=((1, "One"),))


class VerboseNameField(models.Model):
    id = models.AutoField("verbose pk", primary_key=True)
    field1 = models.BigIntegerField("verbose field1")
    field2 = models.BooleanField("verbose field2", default=False)
    field3 = models.CharField("verbose field3", max_length=10)
    field4 = models.DateField("verbose field4")
    field5 = models.DateTimeField("verbose field5")
    field6 = models.DecimalField("verbose field6", max_digits=6, decimal_places=1)
    field7 = models.EmailField("verbose field7")
    field8 = models.FileField("verbose field8", upload_to="unused")
    field9 = models.FilePathField("verbose field9")
    field10 = models.FloatField("verbose field10")
    
    
    field11 = models.IntegerField("verbose field11")
    field12 = models.GenericIPAddressField("verbose field12", protocol="ipv4")
    field13 = models.PositiveIntegerField("verbose field13")
    field14 = models.PositiveSmallIntegerField("verbose field14")
    field15 = models.SlugField("verbose field15")
    field16 = models.SmallIntegerField("verbose field16")
    field17 = models.TextField("verbose field17")
    field18 = models.TimeField("verbose field18")
    field19 = models.URLField("verbose field19")
    field20 = models.UUIDField("verbose field20")
    field21 = models.DurationField("verbose field21")


class GenericIPAddress(models.Model):
    ip = models.GenericIPAddressField(null=True, protocol="ipv4")








class DecimalLessThanOne(models.Model):
    d = models.DecimalField(max_digits=3, decimal_places=3)



class FieldClassAttributeModel(models.Model):
    field_class = models.CharField





class DataModel(models.Model):
    short_data = models.BinaryField(max_length=10, default=b"\x08")
    data = models.BinaryField()






class Document(models.Model):
    myfile = models.FileField(upload_to="unused", unique=True)






if Image:

    class TestImageFieldFile(ImageFieldFile):
        

        def __init__(self, *args, **kwargs):
            self.was_opened = False
            super().__init__(*args, **kwargs)

        def open(self):
            self.was_opened = True
            super().open()

    class TestImageField(models.ImageField):
        attr_class = TestImageFieldFile

    
    temp_storage_dir = tempfile.mkdtemp()
    temp_storage = FileSystemStorage(temp_storage_dir)

    class Person(models.Model):
        

        name = models.CharField(max_length=50)
        mugshot = TestImageField(storage=temp_storage, upload_to="tests")

    class AbstractPersonWithHeight(models.Model):
        

        mugshot = TestImageField(
            storage=temp_storage, upload_to="tests", height_field="mugshot_height"
        )
        mugshot_height = models.PositiveSmallIntegerField()

        class Meta:
            abstract = True

    class PersonWithHeight(AbstractPersonWithHeight):
        

        name = models.CharField(max_length=50)

    class PersonWithHeightAndWidth(models.Model):
        

        name = models.CharField(max_length=50)
        mugshot = TestImageField(
            storage=temp_storage,
            upload_to="tests",
            height_field="mugshot_height",
            width_field="mugshot_width",
        )
        mugshot_height = models.PositiveSmallIntegerField()
        mugshot_width = models.PositiveSmallIntegerField()

    class PersonDimensionsFirst(models.Model):
        

        name = models.CharField(max_length=50)
        mugshot_height = models.PositiveSmallIntegerField()
        mugshot_width = models.PositiveSmallIntegerField()
        mugshot = TestImageField(
            storage=temp_storage,
            upload_to="tests",
            height_field="mugshot_height",
            width_field="mugshot_width",
        )

    class PersonTwoImages(models.Model):
        

        name = models.CharField(max_length=50)
        mugshot_height = models.PositiveSmallIntegerField()
        mugshot_width = models.PositiveSmallIntegerField()
        mugshot = TestImageField(
            storage=temp_storage,
            upload_to="tests",
            height_field="mugshot_height",
            width_field="mugshot_width",
        )
        headshot_height = models.PositiveSmallIntegerField(blank=True, null=True)
        headshot_width = models.PositiveSmallIntegerField(blank=True, null=True)
        headshot = TestImageField(
            blank=True,
            null=True,
            storage=temp_storage,
            upload_to="tests",
            height_field="headshot_height",
            width_field="headshot_width",
        )


class CustomJSONDecoder(json.JSONDecoder):
    def __init__(self, object_hook=None, *args, **kwargs):
        return super().__init__(object_hook=self.as_uuid, *args, **kwargs)

    def as_uuid(self, dct):
        if "uuid" in dct:
            dct["uuid"] = uuid.UUID(dct["uuid"])
        return dct


class JSONModel(models.Model):
    value = models.JSONField()

    class Meta:
        required_db_features = {"supports_json_field"}


class NullableJSONModel(models.Model):
    value = models.JSONField(blank=True, null=True)
    value_custom = models.JSONField(
        encoder=DjangoJSONEncoder,
        decoder=CustomJSONDecoder,
        null=True,
    )

    class Meta:
        required_db_features = {"supports_json_field"}


class RelatedJSONModel(models.Model):
    value = models.JSONField()
    json_model = models.ForeignKey(NullableJSONModel, models.CASCADE)

    class Meta:
        required_db_features = {"supports_json_field"}


class AllFieldsModel(models.Model):
    big_integer = models.BigIntegerField()
    binary = models.BinaryField()
    boolean = models.BooleanField(default=False)
    char = models.CharField(max_length=10)
    date = models.DateField()
    datetime = models.DateTimeField()
    decimal = models.DecimalField(decimal_places=2, max_digits=2)
    duration = models.DurationField()
    email = models.EmailField()
    file_path = models.FilePathField()
    floatf = models.FloatField()
    integer = models.IntegerField()
    generic_ip = models.GenericIPAddressField()
    positive_integer = models.PositiveIntegerField()
    positive_small_integer = models.PositiveSmallIntegerField()
    slug = models.SlugField()
    small_integer = models.SmallIntegerField()
    text = models.TextField()
    time = models.TimeField()
    url = models.URLField()
    uuid = models.UUIDField()

    fo = models.ForeignObject(
        "self",
        on_delete=models.CASCADE,
        from_fields=["positive_integer"],
        to_fields=["id"],
        related_name="reverse",
    )
    fk = models.ForeignKey("self", models.CASCADE, related_name="reverse2")
    m2m = models.ManyToManyField("self")
    oto = models.OneToOneField("self", models.CASCADE)

    object_id = models.PositiveIntegerField()
    content_type = models.ForeignKey(ContentType, models.CASCADE)
    gfk = GenericForeignKey()
    gr = GenericRelation(DataModel)


class ManyToMany(models.Model):
    m2m = models.ManyToManyField("self")





class UUIDModel(models.Model):
    field = models.UUIDField()


class NullableUUIDModel(models.Model):
    field = models.UUIDField(blank=True, null=True)


class PrimaryKeyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)


class RelatedToUUIDModel(models.Model):
    uuid_fk = models.ForeignKey("PrimaryKeyUUIDModel", models.CASCADE)


class UUIDChild(PrimaryKeyUUIDModel):
    pass


class UUIDGrandchild(UUIDChild):
    pass


class GeneratedModel(models.Model):
    a = models.IntegerField()
    b = models.IntegerField()
    field = models.GeneratedField(
        expression=F("a") + F("b"),
        output_field=models.IntegerField(),
        db_persist=True,
    )

    class Meta:
        required_db_features = {"supports_stored_generated_columns"}


class GeneratedModelVirtual(models.Model):
    a = models.IntegerField()
    b = models.IntegerField()
    field = models.GeneratedField(
        expression=F("a") + F("b"),
        output_field=models.IntegerField(),
        db_persist=False,
    )

    class Meta:
        required_db_features = {"supports_virtual_generated_columns"}


class GeneratedModelParams(models.Model):
    field = models.GeneratedField(
        expression=Value("Constant", output_field=models.CharField(max_length=10)),
        output_field=models.CharField(max_length=10),
        db_persist=True,
    )

    class Meta:
        required_db_features = {"supports_stored_generated_columns"}


class GeneratedModelParamsVirtual(models.Model):
    field = models.GeneratedField(
        expression=Value("Constant", output_field=models.CharField(max_length=10)),
        output_field=models.CharField(max_length=10),
        db_persist=False,
    )

    class Meta:
        required_db_features = {"supports_virtual_generated_columns"}


class GeneratedModelOutputFieldDbCollation(models.Model):
    name = models.CharField(max_length=10)
    lower_name = models.GeneratedField(
        expression=Lower("name"),
        output_field=models.CharField(db_collation=test_collation, max_length=11),
        db_persist=True,
    )

    class Meta:
        required_db_features = {"supports_stored_generated_columns"}


class GeneratedModelOutputFieldDbCollationVirtual(models.Model):
    name = models.CharField(max_length=10)
    lower_name = models.GeneratedField(
        expression=Lower("name"),
        db_persist=False,
        output_field=models.CharField(db_collation=test_collation, max_length=11),
    )

    class Meta:
        required_db_features = {"supports_virtual_generated_columns"}


class GeneratedModelNull(models.Model):
    name = models.CharField(max_length=10, null=True)
    lower_name = models.GeneratedField(
        expression=Lower("name"),
        output_field=models.CharField(max_length=10),
        db_persist=True,
        null=True,
    )

    class Meta:
        required_db_features = {"supports_stored_generated_columns"}


class GeneratedModelNullVirtual(models.Model):
    name = models.CharField(max_length=10, null=True)
    lower_name = models.GeneratedField(
        expression=Lower("name"),
        output_field=models.CharField(max_length=10),
        db_persist=False,
        null=True,
    )

    class Meta:
        required_db_features = {"supports_virtual_generated_columns"}