text: import datetime
  import uuid
  
  from django.apps import apps
  from django.conf import settings
  from django.db import models
  from django.urls import reverse
  
  from simple_history import register
  from simple_history.models import HistoricalRecords
  
  from .custom_user.models import CustomUser as User
  from .external.models import AbstractExternal, AbstractExternal2, AbstractExternal3
  
  get_model = apps.get_model
  
  
  class Poll(models.Model):
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
  
      history = HistoricalRecords()
  
      def get_absolute_url(self):
          return reverse("poll-detail", kwargs={"pk": self.pk})
  
  
  class PollWithUniqueQuestion(models.Model):
      question = models.CharField(max_length=200, unique=True)
      pub_date = models.DateTimeField("date published")
  
      history = HistoricalRecords()
  
  
  class PollWithExcludeFields(models.Model):
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
      place = models.TextField(null=True)
  
      history = HistoricalRecords(excluded_fields=["pub_date"])
  
  
  class PollWithExcludedFieldsWithDefaults(models.Model):
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
      expiration_time = models.DateField(default=datetime.date(2030, 12, 12))
      place = models.TextField(null=True)
      min_questions = models.PositiveIntegerField(default=1)
      max_questions = models.PositiveIntegerField()
  
      history = HistoricalRecords(
          excluded_fields=[
              "pub_date",
              "expiration_time",
              "place",
              "min_questions",
              "max_questions",
          ]
      )
  
  
  class PollWithExcludedFKField(models.Model):
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
      place = models.ForeignKey("Place", on_delete=models.CASCADE)
  
      history = HistoricalRecords(excluded_fields=["place"])
  
  
  class AlternativePollManager(models.Manager):
      def get_queryset(self):
          return super(AlternativePollManager, self).get_queryset().exclude(id=1)
  
  
  class PollWithAlternativeManager(models.Model):
      some_objects = AlternativePollManager()
      all_objects = models.Manager()
  
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
  
      history = HistoricalRecords()
  
  
  class IPAddressHistoricalModel(models.Model):
      ip_address = models.GenericIPAddressField()
  
      class Meta:
          abstract = True
  
  
  class PollWithHistoricalIPAddress(models.Model):
      question = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")
  
      history = HistoricalRecords(bases=[IPAddressHistoricalModel])
  
      def get_absolute_url(self):
          return reverse("poll-detail", kwargs={"pk": self.pk})
  
  
  class CustomAttrNameForeignKey(models.ForeignKey):
      def __init__(self, *args, **kwargs):
          self.attr_name = kwargs.pop("attr_name", None)
          super(CustomAttrNameForeignKey, self).__init__(*args, **kwargs)
  
      def get_attname(self):
          return self.attr_name or super(CustomAttrNameForeignKey, self).get_attname()
  
      def deconstruct(self):
          name, path, args, kwargs = super(CustomAttrNameForeignKey, self).deconstruct()
          if self.attr_name:
              kwargs["attr_name"] = self.attr_name
          return name, path, args, kwargs
  
  
  class ModelWithCustomAttrForeignKey(models.Model):
      poll = CustomAttrNameForeignKey(Poll, models.CASCADE, attr_name="custom_poll")
      history = HistoricalRecords()
  
  
  class CustomAttrNameOneToOneField(models.OneToOneField):
      def __init__(self, *args, **kwargs):
          self.attr_name = kwargs.pop("attr_name", None)
          super(CustomAttrNameOneToOneField, self).__init__(*args, **kwargs)
  
      def get_attname(self):
          return self.attr_name or super(CustomAttrNameOneToOneField, self).get_attname()
  
      def deconstruct(self):
          name, path, args, kwargs = super(
              CustomAttrNameOneToOneField, self
          ).deconstruct()
          if self.attr_name:
              kwargs["attr_name"] = self.attr_name
          return name, path, args, kwargs
  
  
  class ModelWithCustomAttrOneToOneField(models.Model):
      poll = CustomAttrNameOneToOneField(Poll, models.CASCADE, attr_name="custom_poll")
      history = HistoricalRecords(excluded_field_kwargs={"poll": set(["attr_name"])})
  
  
  class Temperature(models.Model):
      location = models.CharField(max_length=200)
      temperature = models.IntegerField()
  
      history = HistoricalRecords()
      __history_date = None
  
      @property
      def _history_date(self):
          return self.__history_date
  
      @_history_date.setter
      def _history_date(self, value):
          self.__history_date = value
  
  
  class WaterLevel(models.Model):
      waters = models.CharField(max_length=200)
      level = models.IntegerField()
      date = models.DateTimeField()
  
      history = HistoricalRecords(cascade_delete_history=True)
  
      @property
      def _history_date(self):
          return self.date
  
  
  class Choice(models.Model):
      poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
      choice = models.CharField(max_length=200)
      votes = models.IntegerField()
  
  
  register(Choice)
  
  
  class Voter(models.Model):
      user = models.ForeignKey(User, on_delete=models.CASCADE)
      choice = models.ForeignKey(Choice, on_delete=models.CASCADE, related_name="voters")
  
      def __str__(self):
          return "Voter object"
  
  
  class HistoricalRecordsVerbose(HistoricalRecords):
      def get_extra_fields(self, model, fields):
          def verbose_str(self):
              return "%s changed by %s as of %s" % (
                  self.history_object,
                  self.history_user,
                  self.history_date,
              )
  
          extra_fields = super(HistoricalRecordsVerbose, self).get_extra_fields(
              model, fields
          )
          extra_fields["__str__"] = verbose_str
          return extra_fields
  
  
  register(Voter, records_class=HistoricalRecordsVerbose)
  
  
  class Place(models.Model):
      name = models.CharField(max_length=100)
  
  
  class Restaurant(Place):
      rating = models.IntegerField()
  
      updates = HistoricalRecords()
  
  
  class Person(models.Model):
      name = models.CharField(max_length=100)
  
      history = HistoricalRecords()
  
      def save(self, *args, **kwargs):
          if hasattr(self, "skip_history_when_saving"):
              raise RuntimeError("error while saving")
          else:
              super(Person, self).save(*args, **kwargs)
  
  
  class FileModel(models.Model):
      title = models.CharField(max_length=100)
      file = models.FileField(upload_to="files")
      history = HistoricalRecords()
  
  
  # Set SIMPLE_HISTORY_FILEFIELD_TO_CHARFIELD
  setattr(settings, "SIMPLE_HISTORY_FILEFIELD_TO_CHARFIELD", True)
  
  
  class CharFieldFileModel(models.Model):
      title = models.CharField(max_length=100)
      file = models.FileField(upload_to="files")
      history = HistoricalRecords()
  
  
  # Clear SIMPLE_HISTORY_FILEFIELD_TO_CHARFIELD
  delattr(settings, "SIMPLE_HISTORY_FILEFIELD_TO_CHARFIELD")
  
  
  class Document(models.Model):
      changed_by = models.ForeignKey(
          User, on_delete=models.CASCADE, null=True, blank=True
      )
      history = HistoricalRecords()
  
      @property
      def _history_user(self):
          try:
              return self.changed_by
          except User.DoesNotExist:
              return None
  
  
  class Paper(Document):
      history = HistoricalRecords()
  
      @Document._history_user.setter
      def _history_user(self, value):
          self.changed_by = value
  
  
  class Profile(User):
      date_of_birth = models.DateField()
  
  
  class AdminProfile(models.Model):
      profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
  
  
  class State(models.Model):
      library = models.ForeignKey("Library", on_delete=models.CASCADE, null=True)
      history = HistoricalRecords()
  
  
  class Book(models.Model):
      isbn = models.CharField(max_length=15, primary_key=True)
      history = HistoricalRecords(verbose_name="dead trees")
  
  
  class HardbackBook(Book):
      price = models.FloatField()
  
  
  class Bookcase(models.Model):
      books = models.ForeignKey(HardbackBook, on_delete=models.CASCADE)
  
  
  class Library(models.Model):
      book = models.ForeignKey(Book, on_delete=models.CASCADE, null=True)
      history = HistoricalRecords()
  
      class Meta:
          verbose_name = "quiet please"
  
  
  class BaseModel(models.Model):
      pass
  
  
  class FirstLevelInheritedModel(BaseModel):
      pass
  
  
  class SecondLevelInheritedModel(FirstLevelInheritedModel):
      pass
  
  
  class AbstractBase(models.Model):
      class Meta:
          abstract = True
  
  
  class ConcreteAttr(AbstractBase):
      history = HistoricalRecords(bases=[AbstractBase])
  
  
  class ConcreteUtil(AbstractBase):
      pass
  
  
  register(ConcreteUtil, bases=[AbstractBase])
  
  
  class MultiOneToOne(models.Model):
      fk = models.ForeignKey(SecondLevelInheritedModel, on_delete=models.CASCADE)
  
  
  class SelfFK(models.Model):
      fk = models.ForeignKey("self", on_delete=models.CASCADE, null=True)
      history = HistoricalRecords()
  
  
  register(User, app="simple_history.tests", manager_name="histories")
  
  
  class ExternalModelWithAppLabel(models.Model):
      name = models.CharField(max_length=100)
      history = HistoricalRecords()
  
      class Meta:
          app_label = "external"
  
  
  class ExternalModelSpecifiedWithAppParam(models.Model):
      name = models.CharField(max_length=100)
  
  
  register(
      ExternalModelSpecifiedWithAppParam,
      app="simple_history.tests.external",
      manager_name="histories",
  )
  
  
  class UnicodeVerboseName(models.Model):
      name = models.CharField(max_length=100)
      history = HistoricalRecords()
  
      class Meta:
          verbose_name = "\u570b"
  
  
  class CustomFKError(models.Model):
      fk = models.ForeignKey(SecondLevelInheritedModel, on_delete=models.CASCADE)
      history = HistoricalRecords()
  
  
  class Series(models.Model):
      """A series of works, like a trilogy of books."""
  
      name = models.CharField(max_length=100)
      author = models.CharField(max_length=100)
  
  
  class SeriesWork(models.Model):
      series = models.ForeignKey("Series", on_delete=models.CASCADE, related_name="works")
      title = models.CharField(max_length=100)
      history = HistoricalRecords()
  
      class Meta:
          order_with_respect_to = "series"
  
  
  class PollInfo(models.Model):
      poll = models.OneToOneField(Poll, on_delete=models.CASCADE, primary_key=True)
      history = HistoricalRecords()
  
  
  class UserAccessorDefault(models.Model):
      pass
  
  
  class UserAccessorOverride(models.Model):
      pass
  
  
  class Employee(models.Model):
      manager = models.OneToOneField("Employee", null=True, on_delete=models.CASCADE)
      history = HistoricalRecords()
  
  
  class Country(models.Model):
      code = models.CharField(max_length=15, unique=True)
  
  
  class Province(models.Model):
      country = models.ForeignKey(Country, on_delete=models.CASCADE, to_field="code")
      history = HistoricalRecords()
  
  
  class City(models.Model):
      country = models.ForeignKey(
          Country, on_delete=models.CASCADE, db_column="countryCode"
      )
      history = HistoricalRecords()
  
  
  class Planet(models.Model):
      star = models.CharField(max_length=30)
      history = HistoricalRecords()
  
      def __str__(self):
          return self.star
  
      class Meta:
          verbose_name = "Planet"
  
  
  class Contact(models.Model):
      name = models.CharField(max_length=30)
      email = models.EmailField(max_length=255, unique=True)
      history = HistoricalRecords(table_name="contacts_history")
  
  
  class ContactRegister(models.Model):
      name = models.CharField(max_length=30)
      email = models.EmailField(max_length=255, unique=True)
  
  
  register(ContactRegister, table_name="contacts_register_history")
  
  
  class ModelWithHistoryInDifferentApp(models.Model):
      name = models.CharField(max_length=30)
      history = HistoricalRecords(app="external")
  
  
  class ModelWithHistoryInDifferentDb(models.Model):
      name = models.CharField(max_length=30)
      history = HistoricalRecords()
  
  
  class ModelWithHistoryUsingBaseModelDb(models.Model):
      name = models.CharField(max_length=30)
      history = HistoricalRecords(use_base_model_db=True)
  
  
  class ModelWithFkToModelWithHistoryUsingBaseModelDb(models.Model):
      fk = models.ForeignKey(
          ModelWithHistoryUsingBaseModelDb, on_delete=models.CASCADE, null=True
      )
      history = HistoricalRecords(use_base_model_db=True)
  
  
  ###############################################################################
  #
  # Inheritance examples
  #
  ###############################################################################
  
  
  class TrackedAbstractBaseA(models.Model):
      history = HistoricalRecords(inherit=True)
  
      class Meta:
          abstract = True
  
  
  class TrackedAbstractBaseB(models.Model):
      history_b = HistoricalRecords(inherit=True)
  
      class Meta:
          abstract = True
  
  
  class UntrackedAbstractBase(models.Model):
      class Meta:
          abstract = True
  
  
  class TrackedConcreteBase(models.Model):
      history = HistoricalRecords(inherit=True)
  
  
  class UntrackedConcreteBase(models.Model):
      pass
  
  
  class ConcreteExternal(AbstractExternal):
      name = models.CharField(max_length=50)
  
      class Meta:
          app_label = "tests"
  
  
  class ConcreteExternal2(AbstractExternal):
      name = models.CharField(max_length=50)
  
      class Meta:
          pass  # Don't set app_label to test inherited module path
  
  
  class TrackedWithAbstractBase(TrackedAbstractBaseA):
      pass
  
  
  class TrackedWithConcreteBase(TrackedConcreteBase):
      pass
  
  
  class InheritTracking1(TrackedAbstractBaseA, UntrackedConcreteBase):
      pass
  
  
  class BaseInheritTracking2(TrackedAbstractBaseA):
      pass
  
  
  class InheritTracking2(BaseInheritTracking2):
      pass
  
  
  class BaseInheritTracking3(TrackedAbstractBaseA):
      pass
  
  
  class InheritTracking3(BaseInheritTracking3):
      pass
  
  
  class InheritTracking4(TrackedAbstractBaseA):
      pass
  
  
  class BasePlace(models.Model):
      name = models.CharField(max_length=50)
      history = HistoricalRecords(inherit=True)
  
  
  class InheritedRestaurant(BasePlace):
      serves_hot_dogs = models.BooleanField(default=False)
  
  
  class BucketMember(models.Model):
      name = models.CharField(max_length=30)
      user = models.OneToOneField(
          User, related_name="bucket_member", on_delete=models.CASCADE
      )
  
  
  class BucketData(models.Model):
      changed_by = models.ForeignKey(
          BucketMember, on_delete=models.SET_NULL, null=True, blank=True
      )
      history = HistoricalRecords(user_model=BucketMember)
  
      @property
      def _history_user(self):
          return self.changed_by
  
  
  def get_bucket_member_changed_by(instance, **kwargs):
      try:
          return instance.changed_by
      except AttributeError:
          return None
  
  
  class BucketDataRegisterChangedBy(models.Model):
      changed_by = models.ForeignKey(
          BucketMember, on_delete=models.SET_NULL, null=True, blank=True
      )
  
  
  register(
      BucketDataRegisterChangedBy,
      user_model=BucketMember,
      get_user=get_bucket_member_changed_by,
  )
  
  
  def get_bucket_member_request_user(request, **kwargs):
      try:
          return request.user.bucket_member
      except AttributeError:
          return None
  
  
  class BucketDataRegisterRequestUser(models.Model):
      data = models.CharField(max_length=30)
  
      def get_absolute_url(self):
          return reverse("bucket_data-detail", kwargs={"pk": self.pk})
  
  
  register(
      BucketDataRegisterRequestUser,
      user_model=BucketMember,
      get_user=get_bucket_member_request_user,
  )
  
  
  class UUIDModel(models.Model):
      id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
      history = HistoricalRecords(history_id_field=models.UUIDField(default=uuid.uuid4))
  
  
  class UUIDRegisterModel(models.Model):
      id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  
  
  register(UUIDRegisterModel, history_id_field=models.UUIDField(default=uuid.uuid4))
  
  # Set the SIMPLE_HISTORY_HISTORY_ID_USE_UUID
  setattr(settings, "SIMPLE_HISTORY_HISTORY_ID_USE_UUID", True)
  
  
  class UUIDDefaultModel(models.Model):
      id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
      history = HistoricalRecords()
  
  
  # Clear the SIMPLE_HISTORY_HISTORY_ID_USE_UUID
  delattr(settings, "SIMPLE_HISTORY_HISTORY_ID_USE_UUID")
  
  # Set the SIMPLE_HISTORY_HISTORY_CHANGE_REASON_FIELD
  setattr(settings, "SIMPLE_HISTORY_HISTORY_CHANGE_REASON_USE_TEXT_FIELD", True)
  
  
  class DefaultTextFieldChangeReasonModel(models.Model):
      greeting = models.CharField(max_length=100)
      history = HistoricalRecords()
  
  
  # Clear the SIMPLE_HISTORY_HISTORY_CHANGE_REASON_FIELD
  delattr(settings, "SIMPLE_HISTORY_HISTORY_CHANGE_REASON_USE_TEXT_FIELD")
  
  
  class UserTextFieldChangeReasonModel(models.Model):
      greeting = models.CharField(max_length=100)
      history = HistoricalRecords(history_change_reason_field=models.TextField(null=True))
  
  
  class CharFieldChangeReasonModel(models.Model):
      greeting = models.CharField(max_length=100)
      history = HistoricalRecords()
  
  
  class CustomManagerNameModel(models.Model):
      name = models.CharField(max_length=15)
      log = HistoricalRecords()
  
  
  #
  # Following classes test the "custom_model_name" option
  #
  
  
  class OverrideModelNameAsString(models.Model):
      name = models.CharField(max_length=15, unique=True)
      history = HistoricalRecords(custom_model_name="MyHistoricalCustomNameModel")
  
  
  class OverrideModelNameAsCallable(models.Model):
      name = models.CharField(max_length=15, unique=True)
      history = HistoricalRecords(custom_model_name=lambda x: "Audit{}".format(x))
  
  
  class AbstractModelCallable1(models.Model):
      history = HistoricalRecords(
          inherit=True, custom_model_name=lambda x: "Audit{}".format(x)
      )
  
      class Meta:
          abstract = True
  
  
  class OverrideModelNameUsingBaseModel1(AbstractModelCallable1):
      name = models.CharField(max_length=15, unique=True)
  
  
  class OverrideModelNameUsingExternalModel1(AbstractExternal2):
      name = models.CharField(max_length=15, unique=True)
  
  
  class OverrideModelNameUsingExternalModel2(AbstractExternal3):
      name = models.CharField(max_length=15, unique=True)
  
  
  class OverrideModelNameRegisterMethod1(models.Model):
      name = models.CharField(max_length=15, unique=True)
  
  
  register(
      OverrideModelNameRegisterMethod1,
      custom_model_name="MyOverrideModelNameRegisterMethod1",
  )
  
  
  class OverrideModelNameRegisterMethod2(models.Model):
      name = models.CharField(max_length=15, unique=True)
  
  
  class ForeignKeyToSelfModel(models.Model):
      fk_to_self = models.ForeignKey(
          "ForeignKeyToSelfModel", null=True, related_name="+", on_delete=models.CASCADE
      )
      fk_to_self_using_str = models.ForeignKey(
          "self", null=True, related_name="+", on_delete=models.CASCADE
      )
      history = HistoricalRecords()
  
  
  class Street(models.Model):
      name = models.CharField(max_length=150)
      log = HistoricalRecords(related_name="history")
  
  
  class ManyToManyModelOther(models.Model):
      name = models.CharField(max_length=15, unique=True)
  
  
  class BulkCreateManyToManyModel(models.Model):
      name = models.CharField(max_length=15, unique=True)
      other = models.ManyToManyField(ManyToManyModelOther)
      history = HistoricalRecords()
  
  
  class ModelWithExcludedManyToMany(models.Model):
      name = models.CharField(max_length=15, unique=True)
      other = models.ManyToManyField(ManyToManyModelOther)
      history = HistoricalRecords(excluded_fields=["other"])
  