1. """
    
  2. By specifying the 'proxy' Meta attribute, model subclasses can specify that
    
  3. they will take data directly from the table of their base class table rather
    
  4. than using a new table of their own. This allows them to act as simple proxies,
    
  5. providing a modified interface to the data from the base class.
    
  6. """
    
  7. from django.db import models
    
  8. 
    
  9. # A couple of managers for testing managing overriding in proxy model cases.
    
  10. 
    
  11. 
    
  12. class PersonManager(models.Manager):
    
  13.     def get_queryset(self):
    
  14.         return super().get_queryset().exclude(name="fred")
    
  15. 
    
  16. 
    
  17. class SubManager(models.Manager):
    
  18.     def get_queryset(self):
    
  19.         return super().get_queryset().exclude(name="wilma")
    
  20. 
    
  21. 
    
  22. class Person(models.Model):
    
  23.     """
    
  24.     A simple concrete base class.
    
  25.     """
    
  26. 
    
  27.     name = models.CharField(max_length=50)
    
  28. 
    
  29.     objects = PersonManager()
    
  30. 
    
  31.     def __str__(self):
    
  32.         return self.name
    
  33. 
    
  34. 
    
  35. class Abstract(models.Model):
    
  36.     """
    
  37.     A simple abstract base class, to be used for error checking.
    
  38.     """
    
  39. 
    
  40.     data = models.CharField(max_length=10)
    
  41. 
    
  42.     class Meta:
    
  43.         abstract = True
    
  44. 
    
  45. 
    
  46. class MyPerson(Person):
    
  47.     """
    
  48.     A proxy subclass, this should not get a new table. Overrides the default
    
  49.     manager.
    
  50.     """
    
  51. 
    
  52.     class Meta:
    
  53.         proxy = True
    
  54.         ordering = ["name"]
    
  55.         permissions = (("display_users", "May display users information"),)
    
  56. 
    
  57.     objects = SubManager()
    
  58.     other = PersonManager()
    
  59. 
    
  60.     def has_special_name(self):
    
  61.         return self.name.lower() == "special"
    
  62. 
    
  63. 
    
  64. class ManagerMixin(models.Model):
    
  65.     excluder = SubManager()
    
  66. 
    
  67.     class Meta:
    
  68.         abstract = True
    
  69. 
    
  70. 
    
  71. class OtherPerson(Person, ManagerMixin):
    
  72.     """
    
  73.     A class with the default manager from Person, plus a secondary manager.
    
  74.     """
    
  75. 
    
  76.     class Meta:
    
  77.         proxy = True
    
  78.         ordering = ["name"]
    
  79. 
    
  80. 
    
  81. class StatusPerson(MyPerson):
    
  82.     """
    
  83.     A non-proxy subclass of a proxy, it should get a new table.
    
  84.     """
    
  85. 
    
  86.     status = models.CharField(max_length=80)
    
  87. 
    
  88.     objects = models.Manager()
    
  89. 
    
  90. 
    
  91. # We can even have proxies of proxies (and subclass of those).
    
  92. 
    
  93. 
    
  94. class MyPersonProxy(MyPerson):
    
  95.     class Meta:
    
  96.         proxy = True
    
  97. 
    
  98. 
    
  99. class LowerStatusPerson(MyPersonProxy):
    
  100.     status = models.CharField(max_length=80)
    
  101. 
    
  102.     objects = models.Manager()
    
  103. 
    
  104. 
    
  105. class User(models.Model):
    
  106.     name = models.CharField(max_length=100)
    
  107. 
    
  108.     def __str__(self):
    
  109.         return self.name
    
  110. 
    
  111. 
    
  112. class UserProxy(User):
    
  113.     class Meta:
    
  114.         proxy = True
    
  115. 
    
  116. 
    
  117. class AnotherUserProxy(User):
    
  118.     class Meta:
    
  119.         proxy = True
    
  120. 
    
  121. 
    
  122. class UserProxyProxy(UserProxy):
    
  123.     class Meta:
    
  124.         proxy = True
    
  125. 
    
  126. 
    
  127. class MultiUserProxy(UserProxy, AnotherUserProxy):
    
  128.     class Meta:
    
  129.         proxy = True
    
  130. 
    
  131. 
    
  132. # We can still use `select_related()` to include related models in our querysets.
    
  133. 
    
  134. 
    
  135. class Country(models.Model):
    
  136.     name = models.CharField(max_length=50)
    
  137. 
    
  138. 
    
  139. class State(models.Model):
    
  140.     name = models.CharField(max_length=50)
    
  141.     country = models.ForeignKey(Country, models.CASCADE)
    
  142. 
    
  143.     def __str__(self):
    
  144.         return self.name
    
  145. 
    
  146. 
    
  147. class StateProxy(State):
    
  148.     class Meta:
    
  149.         proxy = True
    
  150. 
    
  151. 
    
  152. # Proxy models still works with filters (on related fields)
    
  153. # and select_related, even when mixed with model inheritance
    
  154. 
    
  155. 
    
  156. class BaseUser(models.Model):
    
  157.     name = models.CharField(max_length=255)
    
  158. 
    
  159.     def __str__(self):
    
  160.         return ":".join(
    
  161.             (
    
  162.                 self.__class__.__name__,
    
  163.                 self.name,
    
  164.             )
    
  165.         )
    
  166. 
    
  167. 
    
  168. class TrackerUser(BaseUser):
    
  169.     status = models.CharField(max_length=50)
    
  170. 
    
  171. 
    
  172. class ProxyTrackerUser(TrackerUser):
    
  173.     class Meta:
    
  174.         proxy = True
    
  175. 
    
  176. 
    
  177. class Issue(models.Model):
    
  178.     summary = models.CharField(max_length=255)
    
  179.     assignee = models.ForeignKey(
    
  180.         ProxyTrackerUser, models.CASCADE, related_name="issues"
    
  181.     )
    
  182. 
    
  183.     def __str__(self):
    
  184.         return ":".join(
    
  185.             (
    
  186.                 self.__class__.__name__,
    
  187.                 self.summary,
    
  188.             )
    
  189.         )
    
  190. 
    
  191. 
    
  192. class Bug(Issue):
    
  193.     version = models.CharField(max_length=50)
    
  194.     reporter = models.ForeignKey(BaseUser, models.CASCADE)
    
  195. 
    
  196. 
    
  197. class ProxyBug(Bug):
    
  198.     """
    
  199.     Proxy of an inherited class
    
  200.     """
    
  201. 
    
  202.     class Meta:
    
  203.         proxy = True
    
  204. 
    
  205. 
    
  206. class ProxyProxyBug(ProxyBug):
    
  207.     """
    
  208.     A proxy of proxy model with related field
    
  209.     """
    
  210. 
    
  211.     class Meta:
    
  212.         proxy = True
    
  213. 
    
  214. 
    
  215. class Improvement(Issue):
    
  216.     """
    
  217.     A model that has relation to a proxy model
    
  218.     or to a proxy of proxy model
    
  219.     """
    
  220. 
    
  221.     version = models.CharField(max_length=50)
    
  222.     reporter = models.ForeignKey(ProxyTrackerUser, models.CASCADE)
    
  223.     associated_bug = models.ForeignKey(ProxyProxyBug, models.CASCADE)
    
  224. 
    
  225. 
    
  226. class ProxyImprovement(Improvement):
    
  227.     class Meta:
    
  228.         proxy = True