old_contents: from django.db import models
  
  from cms.models import Page, Title
  
  
  class BaseExtension(models.Model):
      public_extension = models.OneToOneField('self', null=True, editable=False, related_name='draft_extension')
      extended_object = None
  
      class Meta:
          abstract = True
  
      def get_page(self):
          raise NotImplementedError('Function must be overwritten in subclasses and return the extended page object.')
  
      def copy_relations(self, oldinstance):
          """
          Copy relations like many to many or foreign key relations to the public version.
          Similar to the same named cms plugin function.
  
          :param oldinstance: the draft version of the extension
          """
  
          pass
  
      def copy_to_public(self, public_object):
          this = self.__class__.objects.get(pk=self.pk)  # get a copy of this instance
          public_extension = self.public_extension  # get the public version of this instance if any
  
          this.extended_object = public_object  # set the new public object
  
          if public_extension:
              this.pk = public_extension.pk  # overwrite current public extension
              this.public_extension = None  # remove public extension or it will point to itself and raise duplicate entry
          else:
              this.pk = None  # create new public extension
              this.save(mark_page=False)
              self.public_extension = this
              self.save(mark_page=False)
  
          this.copy_relations(self)
          this.save(force_update=True, mark_page=False)
  
          return this
  
      def save(self, *args, **kwargs):
          if kwargs.pop('mark_page', True):
              self.get_page().save(no_signals=True)  # mark page unpublished
          return super(BaseExtension, self).save(*args, **kwargs)
  
      def delete(self, *args, **kwargs):
          if kwargs.pop('mark_page', True):
              self.get_page().save(no_signals=True)  # mark page unpublished
          return super(BaseExtension, self).delete(*args, **kwargs)
  
  
  class PageExtension(BaseExtension):
      extended_object = models.ForeignKey(Page, editable=False)
  
      class Meta:
          abstract = True
  
      def get_page(self):
          return self.extended_object
  
  
  class TitleExtension(BaseExtension):
      extended_object = models.ForeignKey(Title, editable=False)
  
      class Meta:
          abstract = True
  
      def get_page(self):
          return self.extended_object.page
  
  
  
  
new_contents: from django.db import models
  
  from cms.models import Page, Title
  
  
  class BaseExtension(models.Model):
      public_extension = models.OneToOneField('self', null=True, editable=False, related_name='draft_extension')
      extended_object = None
  
      class Meta:
          abstract = True
  
      def get_page(self):
          raise NotImplementedError('Function must be overwritten in subclasses and return the extended page object.')
  
      def copy_relations(self, oldinstance):
          """
          Copy relations like many to many or foreign key relations to the public version.
          Similar to the same named cms plugin function.
  
          :param oldinstance: the draft version of the extension
          """
  
          pass
  
      def copy_to_public(self, public_object):
          this = self.__class__.objects.get(pk=self.pk)  # get a copy of this instance
          public_extension = self.public_extension  # get the public version of this instance if any
  
          this.extended_object = public_object  # set the new public object
  
          if public_extension:
              this.pk = public_extension.pk  # overwrite current public extension
              this.public_extension = None  # remove public extension or it will point to itself and raise duplicate entry
          else:
              this.pk = None  # create new public extension
              this.save(mark_page=False)
              self.public_extension = this
              self.save(mark_page=False)
  
          this.copy_relations(self)
          this.save(force_update=True, mark_page=False)
  
          return this
  
      def save(self, *args, **kwargs):
          if kwargs.pop('mark_page', True):
              self.get_page().save(no_signals=True)  # mark page unpublished
          return super(BaseExtension, self).save(*args, **kwargs)
  
      def delete(self, *args, **kwargs):
          if kwargs.pop('mark_page', True):
              self.get_page().save(no_signals=True)  # mark page unpublished
          return super(BaseExtension, self).delete(*args, **kwargs)
  
  
  class PageExtension(BaseExtension):
      extended_object = models.OneToOneField(Page, editable=False)
  
      class Meta:
          abstract = True
  
      def get_page(self):
          return self.extended_object
  
  
  class TitleExtension(BaseExtension):
      extended_object = models.OneToOneField(Title, editable=False)
  
      class Meta:
          abstract = True
  
      def get_page(self):
          return self.extended_object.page
  
  
  
  
subject: use OneToOneField to allow optimising with select_related