openedx-learning 0.20.0__py2.py3-none-any.whl → 0.23.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -104,3 +104,47 @@ class PublishLogRecord(models.Model):
104
104
  ]
105
105
  verbose_name = "Publish Log Record"
106
106
  verbose_name_plural = "Publish Log Records"
107
+
108
+
109
+ class Published(models.Model):
110
+ """
111
+ Find the currently published version of an entity.
112
+
113
+ Notes:
114
+
115
+ * There is only ever one published PublishableEntityVersion per
116
+ PublishableEntity at any given time.
117
+ * It may be possible for a PublishableEntity to exist only as a Draft (and thus
118
+ not show up in this table).
119
+ * If a row exists for a PublishableEntity, but the ``version`` field is
120
+ None, it means that the entity was published at some point, but is no
121
+ longer published now–i.e. it's functionally "deleted", even though all
122
+ the version history is preserved behind the scenes.
123
+
124
+ TODO: Do we need to create a (redundant) title field in this model so that
125
+ we can more efficiently search across titles within a LearningPackage?
126
+ Probably not an immediate concern because the number of rows currently
127
+ shouldn't be > 10,000 in the more extreme cases.
128
+
129
+ TODO: Do we need to make a "most_recently" published version when an entry
130
+ is unpublished/deleted?
131
+ """
132
+
133
+ entity = models.OneToOneField(
134
+ PublishableEntity,
135
+ on_delete=models.CASCADE,
136
+ primary_key=True,
137
+ )
138
+ version = models.OneToOneField(
139
+ PublishableEntityVersion,
140
+ on_delete=models.RESTRICT,
141
+ null=True,
142
+ )
143
+ publish_log_record = models.ForeignKey(
144
+ PublishLogRecord,
145
+ on_delete=models.RESTRICT,
146
+ )
147
+
148
+ class Meta:
149
+ verbose_name = "Published Entity"
150
+ verbose_name_plural = "Published Entities"
@@ -62,8 +62,7 @@ def create_unit_version(
62
62
  version_num: int,
63
63
  *,
64
64
  title: str,
65
- publishable_entities_pks: list[int],
66
- entity_version_pks: list[int | None],
65
+ entity_rows: list[publishing_api.ContainerEntityRow],
67
66
  created: datetime,
68
67
  created_by: int | None = None,
69
68
  ) -> UnitVersion:
@@ -75,11 +74,10 @@ def create_unit_version(
75
74
  `create_next_unit_version()` instead.
76
75
 
77
76
  Args:
78
- unit_pk: The unit ID.
77
+ unit: The unit object.
79
78
  version_num: The version number.
80
79
  title: The title.
81
- publishable_entities_pk: The publishable entities.
82
- entity: The entity.
80
+ entity_rows: child entities/versions
83
81
  created: The creation date.
84
82
  created_by: The user who created the unit.
85
83
  """
@@ -87,8 +85,7 @@ def create_unit_version(
87
85
  unit.pk,
88
86
  version_num,
89
87
  title=title,
90
- publishable_entities_pks=publishable_entities_pks,
91
- entity_version_pks=entity_version_pks,
88
+ entity_rows=entity_rows,
92
89
  created=created,
93
90
  created_by=created_by,
94
91
  container_version_cls=UnitVersion,
@@ -97,30 +94,34 @@ def create_unit_version(
97
94
 
98
95
  def _pub_entities_for_components(
99
96
  components: list[Component | ComponentVersion] | None,
100
- ) -> tuple[list[int], list[int | None]] | tuple[None, None]:
97
+ ) -> list[publishing_api.ContainerEntityRow] | None:
101
98
  """
102
99
  Helper method: given a list of Component | ComponentVersion, return the
103
- lists of publishable_entities_pks and entity_version_pks needed for the
104
- base container APIs.
100
+ list of ContainerEntityRows needed for the base container APIs.
105
101
 
106
102
  ComponentVersion is passed when we want to pin a specific version, otherwise
107
103
  Component is used for unpinned.
108
104
  """
109
105
  if components is None:
110
106
  # When these are None, that means don't change the entities in the list.
111
- return None, None
107
+ return None
112
108
  for c in components:
113
109
  if not isinstance(c, (Component, ComponentVersion)):
114
110
  raise TypeError("Unit components must be either Component or ComponentVersion.")
115
- publishable_entities_pks = [
116
- (c.publishable_entity_id if isinstance(c, Component) else c.component.publishable_entity_id)
111
+ return [
112
+ (
113
+ publishing_api.ContainerEntityRow(
114
+ entity_pk=c.publishable_entity_id,
115
+ version_pk=None,
116
+ ) if isinstance(c, Component)
117
+ else # isinstance(c, ComponentVersion)
118
+ publishing_api.ContainerEntityRow(
119
+ entity_pk=c.component.publishable_entity_id,
120
+ version_pk=c.pk,
121
+ )
122
+ )
117
123
  for c in components
118
124
  ]
119
- entity_version_pks = [
120
- (cv.pk if isinstance(cv, ComponentVersion) else None)
121
- for cv in components
122
- ]
123
- return publishable_entities_pks, entity_version_pks
124
125
 
125
126
 
126
127
  def create_next_unit_version(
@@ -143,12 +144,11 @@ def create_next_unit_version(
143
144
  created: The creation date.
144
145
  created_by: The user who created the unit.
145
146
  """
146
- publishable_entities_pks, entity_version_pks = _pub_entities_for_components(components)
147
+ entity_rows = _pub_entities_for_components(components)
147
148
  unit_version = publishing_api.create_next_container_version(
148
149
  unit.pk,
149
150
  title=title,
150
- publishable_entities_pks=publishable_entities_pks,
151
- entity_version_pks=entity_version_pks,
151
+ entity_rows=entity_rows,
152
152
  created=created,
153
153
  created_by=created_by,
154
154
  container_version_cls=UnitVersion,
@@ -177,7 +177,7 @@ def create_unit_and_version(
177
177
  created_by: The user who created the unit.
178
178
  can_stand_alone: Set to False when created as part of containers
179
179
  """
180
- publishable_entities_pks, entity_version_pks = _pub_entities_for_components(components)
180
+ entity_rows = _pub_entities_for_components(components)
181
181
  with atomic():
182
182
  unit = create_unit(
183
183
  learning_package_id,
@@ -190,8 +190,7 @@ def create_unit_and_version(
190
190
  unit,
191
191
  1,
192
192
  title=title,
193
- publishable_entities_pks=publishable_entities_pks or [],
194
- entity_version_pks=entity_version_pks or [],
193
+ entity_rows=entity_rows or [],
195
194
  created=created,
196
195
  created_by=created_by,
197
196
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openedx-learning
3
- Version: 0.20.0
3
+ Version: 0.23.0
4
4
  Summary: Open edX Learning Core and Tagging.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -19,12 +19,12 @@ Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.11
21
21
  License-File: LICENSE.txt
22
- Requires-Dist: djangorestframework<4.0
23
22
  Requires-Dist: attrs
24
- Requires-Dist: celery
25
- Requires-Dist: rules<4.0
26
- Requires-Dist: edx-drf-extensions
27
23
  Requires-Dist: Django
24
+ Requires-Dist: djangorestframework<4.0
25
+ Requires-Dist: edx-drf-extensions
26
+ Requires-Dist: rules<4.0
27
+ Requires-Dist: celery
28
28
  Dynamic: author
29
29
  Dynamic: author-email
30
30
  Dynamic: classifier
@@ -1,4 +1,4 @@
1
- openedx_learning/__init__.py,sha256=WDokxtzsuwd2W-qT4Q9Xle8FEzeUPjSqHq6jSb3YHow,69
1
+ openedx_learning/__init__.py,sha256=_QT8vl820lRjYpoDGXnsI6kcftcuz00aGlyEs_b9UBg,69
2
2
  openedx_learning/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  openedx_learning/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  openedx_learning/api/authoring.py,sha256=AuEegFTT3tAer_3zSxcxqLq3Yd_eilk-Hxt4ESYearA,970
@@ -7,7 +7,7 @@ openedx_learning/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
7
7
  openedx_learning/apps/authoring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  openedx_learning/apps/authoring/collections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  openedx_learning/apps/authoring/collections/admin.py,sha256=f0hySjDMfIphVDEGkCSMIUHoEiqHRA7EE2NiO7lvL4g,1156
10
- openedx_learning/apps/authoring/collections/api.py,sha256=Lui-9mvlUjXSfCcaHrYJc2y2aJ1obJPCIp5hvxYwnkI,5894
10
+ openedx_learning/apps/authoring/collections/api.py,sha256=DaGg73iom7fN9fODajo8B2e9Jkx2syfLEVjip0cAzlQ,7747
11
11
  openedx_learning/apps/authoring/collections/apps.py,sha256=67imy9vnyXml4cfLNGFJhuZr2yx1q92-xz4ih3yJgNU,416
12
12
  openedx_learning/apps/authoring/collections/models.py,sha256=os8EKUVZ2IhMfFo2XN9tklByCUXphEtzAkKAOc0KyW8,8451
13
13
  openedx_learning/apps/authoring/collections/migrations/0001_initial.py,sha256=xcJoqMLROW9FTILYrz6UsyotVu9wBN5tRBwRoAWG6dg,1496
@@ -18,7 +18,7 @@ openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_opt
18
18
  openedx_learning/apps/authoring/collections/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  openedx_learning/apps/authoring/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  openedx_learning/apps/authoring/components/admin.py,sha256=zfEpuBEySMYpUZzygaE2MDoI8SH-2H3xIL20YCSCMLo,4582
21
- openedx_learning/apps/authoring/components/api.py,sha256=PmCtJiyw0Vy4PGSRt9JCStJQv9OJ4FchtOyiY1sfJ-s,25254
21
+ openedx_learning/apps/authoring/components/api.py,sha256=nJZcGXN5gOz8EYX3XHCiDILowNRcm__RxTfTNt5rZZw,22780
22
22
  openedx_learning/apps/authoring/components/apps.py,sha256=Rcydv_FH-rVvuWIFqUezBNOh8DtrZHyozZM2yqX2JKE,778
23
23
  openedx_learning/apps/authoring/components/models.py,sha256=ttZzVnMZTa14-qudrLb4CFuCanEQJT8cuC_iVPH8XTA,10887
24
24
  openedx_learning/apps/authoring/components/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -36,24 +36,27 @@ openedx_learning/apps/authoring/contents/models.py,sha256=8CYrHK7CZ4U3F7Den4ZV_a
36
36
  openedx_learning/apps/authoring/contents/migrations/0001_initial.py,sha256=FtOTmIGX2KHpjw-PHbfRjxkFEomI5CEDhNKCZ7IpFeE,3060
37
37
  openedx_learning/apps/authoring/contents/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  openedx_learning/apps/authoring/publishing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- openedx_learning/apps/authoring/publishing/admin.py,sha256=yPtqznDzlWHj0xpJ_FGFRviyftgPmuql5EoqKLeZQFo,4911
40
- openedx_learning/apps/authoring/publishing/api.py,sha256=tNpDYfQXwjpkp3acVXNItNXN4oCCekGSQa9M5TozXEs,41130
39
+ openedx_learning/apps/authoring/publishing/admin.py,sha256=sLmtttaYIQi8XWw_wOdDD9xbF34g1giMEj5yIN-b-4M,7012
40
+ openedx_learning/apps/authoring/publishing/api.py,sha256=14JojKz57Vl_16JwWcDSOM9JzZm6h0sxAmldmb3SVeE,55712
41
41
  openedx_learning/apps/authoring/publishing/apps.py,sha256=v9PTe3YoICaYT9wfu268ZkVAlnZFvxi-DqYdbRi25bY,750
42
+ openedx_learning/apps/authoring/publishing/contextmanagers.py,sha256=AH5zhr0Tz_gUG9--dfr_oZAu8DMy94n6mnOJuPbWkeU,6723
42
43
  openedx_learning/apps/authoring/publishing/migrations/0001_initial.py,sha256=wvekNV19YRSdxRmQaFnLSn_nCsQlHIucPDVMmgKf_OE,9272
43
44
  openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py,sha256=toI7qJhNukk6hirKfFx9EpqTpzF2O2Yq1VpFJusDn2M,806
44
45
  openedx_learning/apps/authoring/publishing/migrations/0003_containers.py,sha256=k5P1LFkjQT-42yyHE2f57dAMQKafLuJCTRaCBMKWcjc,2519
45
46
  openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py,sha256=RapDZKcjTp5QGgob9DUaf-zl_pQgg-5nz8PZWoXMlVA,549
46
47
  openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py,sha256=Pp4O-VSI75n3UTZZW6CU4TOVIVc5lZvUg5YfMvZyrYM,377
48
+ openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py,sha256=TdioE59_fXCf4ykWhXJfEjyxdDmqbbbLCwLeT1C9irA,3497
49
+ openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py,sha256=EoFFSv52CeiuMGf3KmBvr34sx9N-tv8afdXWVR8wPFA,4154
47
50
  openedx_learning/apps/authoring/publishing/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- openedx_learning/apps/authoring/publishing/models/__init__.py,sha256=Ou6Ks3qxEhel9uHLpzi77jlkb_IHc9_WIfqxOZJuqaE,1059
51
+ openedx_learning/apps/authoring/publishing/models/__init__.py,sha256=ZhpKo4F30VJatp1F-jQSJnKw8AeHFig9E9SlGnxxBCc,1108
49
52
  openedx_learning/apps/authoring/publishing/models/container.py,sha256=GCUD3WTlgvgZSQOKcoOsfhNAfc5pz3Wbs9ClE9mhtB0,2594
50
- openedx_learning/apps/authoring/publishing/models/draft_published.py,sha256=dDZfbTcqLmnOhgIG-H8mhPFLRks_c03VE-ynGD_CNeo,3632
53
+ openedx_learning/apps/authoring/publishing/models/draft_log.py,sha256=7hpbtnnc3yD_3YpH7uqO91FC5KYQkNxtBFSewkIf_AQ,13670
51
54
  openedx_learning/apps/authoring/publishing/models/entity_list.py,sha256=8MyJqDdC8dqJY-N9UAu-WS-ZeFOYuRNMKloSY9wMH1w,3042
52
55
  openedx_learning/apps/authoring/publishing/models/learning_package.py,sha256=1fuNLHD6k0qGuL0jXYGf4-TA5WczgxJrXUdAIM_JNBI,2688
53
- openedx_learning/apps/authoring/publishing/models/publish_log.py,sha256=-uMj1X8umqRM259ucOqNt6POeKDpY5RLdA8XnWXt7Go,4109
56
+ openedx_learning/apps/authoring/publishing/models/publish_log.py,sha256=QD7Fb00yUMWM4HHae_m60JW-TDX8upbQdWCEIdhB0yE,5615
54
57
  openedx_learning/apps/authoring/publishing/models/publishable_entity.py,sha256=-6Fde_sYqaq1AUC4sw4Rf1X9Hh4jun2Py7Xhsl4VWuY,25419
55
58
  openedx_learning/apps/authoring/units/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- openedx_learning/apps/authoring/units/api.py,sha256=nhAATIC0j4We1-3K5yr9FvNr7Dyg-LVHyxfa1ik6IMw,10106
59
+ openedx_learning/apps/authoring/units/api.py,sha256=KJA7Bh7IBE22E6cMSZNp6pamjjA1Vf8EhHw0rvQtlPM,9797
57
60
  openedx_learning/apps/authoring/units/apps.py,sha256=cIzphjDw5sjIZ3NLE911N7IMUa8JQSXMReNl03uI7jg,701
58
61
  openedx_learning/apps/authoring/units/models.py,sha256=eTOwFWC9coQLf0ovx08Mj7zi8mPAWCw9QOznybajRk0,1418
59
62
  openedx_learning/apps/authoring/units/migrations/0001_initial.py,sha256=qM_0JGffxECVgXzncHXfgSE-g8u3L3a14R0M1Bnj_Ys,1129
@@ -71,7 +74,7 @@ openedx_learning/lib/fields.py,sha256=eiGoXMPhRuq25EH2qf6BAODshAQE3DBVdIYAMIUAXW
71
74
  openedx_learning/lib/managers.py,sha256=-Q3gxalSqyPZ9Im4DTROW5tF8wVTZLlmfTe62_xmowY,1643
72
75
  openedx_learning/lib/test_utils.py,sha256=g3KLuepIZbaDBCsaj9711YuqyUx7LD4gXDcfNC-mWdc,527
73
76
  openedx_learning/lib/validators.py,sha256=iqEdEAvFV2tC7Ecssx69kjecpdU8nE87AlDJYrqrsnc,404
74
- openedx_learning-0.20.0.dist-info/licenses/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
77
+ openedx_learning-0.23.0.dist-info/licenses/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
75
78
  openedx_tagging/__init__.py,sha256=V9N8M7f9LYlAbA_DdPUsHzTnWjYRXKGa5qHw9P1JnNI,30
76
79
  openedx_tagging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
80
  openedx_tagging/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -127,7 +130,7 @@ openedx_tagging/core/tagging/rest_api/v1/serializers.py,sha256=0HQD_Jrf6-YpocYfz
127
130
  openedx_tagging/core/tagging/rest_api/v1/urls.py,sha256=dNUKCtUCx_YzrwlbEbpDfjGVQbb2QdJ1VuJCkladj6E,752
128
131
  openedx_tagging/core/tagging/rest_api/v1/views.py,sha256=Hf92cy-tE767DE9FgsZcPKiCYrf5ihfETz8qGKBnuiU,36278
129
132
  openedx_tagging/core/tagging/rest_api/v1/views_import.py,sha256=kbHUPe5A6WaaJ3J1lFIcYCt876ecLNQfd19m7YYub6c,1470
130
- openedx_learning-0.20.0.dist-info/METADATA,sha256=oaXh99UqYsZ_dgDsbiwKAFvtP_kxGCUgDNAl0OBW4VI,9032
131
- openedx_learning-0.20.0.dist-info/WHEEL,sha256=MAQBAzGbXNI3bUmkDsiV_duv8i-gcdnLzw7cfUFwqhU,109
132
- openedx_learning-0.20.0.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
133
- openedx_learning-0.20.0.dist-info/RECORD,,
133
+ openedx_learning-0.23.0.dist-info/METADATA,sha256=a-4VMoLSKMLrTvXd95FvsONcKLBbluQ8skrJ3SuVpPo,9032
134
+ openedx_learning-0.23.0.dist-info/WHEEL,sha256=MAQBAzGbXNI3bUmkDsiV_duv8i-gcdnLzw7cfUFwqhU,109
135
+ openedx_learning-0.23.0.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
136
+ openedx_learning-0.23.0.dist-info/RECORD,,
@@ -1,95 +0,0 @@
1
- """
2
- Draft and Published models
3
- """
4
- from django.db import models
5
-
6
- from .publish_log import PublishLogRecord
7
- from .publishable_entity import PublishableEntity, PublishableEntityVersion
8
-
9
-
10
- class Draft(models.Model):
11
- """
12
- Find the active draft version of an entity (usually most recently created).
13
-
14
- This model mostly only exists to allow us to join against a bunch of
15
- PublishableEntity objects at once and get all their latest drafts. You might
16
- use this together with Published in order to see which Drafts haven't been
17
- published yet.
18
-
19
- A Draft entry should be created whenever a new PublishableEntityVersion is
20
- created. This means there are three possible states:
21
-
22
- 1. No Draft entry for a PublishableEntity: This means a PublishableEntity
23
- was created, but no PublishableEntityVersion was ever made for it, so
24
- there was never a Draft version.
25
- 2. A Draft entry exists and points to a PublishableEntityVersion: This is
26
- the most common state.
27
- 3. A Draft entry exists and points to a null version: This means a version
28
- used to be the draft, but it's been functionally "deleted". The versions
29
- still exist in our history, but we're done using it.
30
-
31
- It would have saved a little space to add this data to the Published model
32
- (and possibly call the combined model something else). Split Modulestore did
33
- this with its active_versions table. I keep it separate here to get a better
34
- separation of lifecycle events: i.e. this table *only* changes when drafts
35
- are updated, not when publishing happens. The Published model only changes
36
- when something is published.
37
- """
38
- # If we're removing a PublishableEntity entirely, also remove the Draft
39
- # entry for it. This isn't a normal operation, but can happen if you're
40
- # deleting an entire LearningPackage.
41
- entity = models.OneToOneField(
42
- PublishableEntity,
43
- on_delete=models.CASCADE,
44
- primary_key=True,
45
- )
46
- version = models.OneToOneField(
47
- PublishableEntityVersion,
48
- on_delete=models.RESTRICT,
49
- null=True,
50
- blank=True,
51
- )
52
-
53
-
54
- class Published(models.Model):
55
- """
56
- Find the currently published version of an entity.
57
-
58
- Notes:
59
-
60
- * There is only ever one published PublishableEntityVersion per
61
- PublishableEntity at any given time.
62
- * It may be possible for a PublishableEntity to exist only as a Draft (and thus
63
- not show up in this table).
64
- * If a row exists for a PublishableEntity, but the ``version`` field is
65
- None, it means that the entity was published at some point, but is no
66
- longer published now–i.e. it's functionally "deleted", even though all
67
- the version history is preserved behind the scenes.
68
-
69
- TODO: Do we need to create a (redundant) title field in this model so that
70
- we can more efficiently search across titles within a LearningPackage?
71
- Probably not an immediate concern because the number of rows currently
72
- shouldn't be > 10,000 in the more extreme cases.
73
-
74
- TODO: Do we need to make a "most_recently" published version when an entry
75
- is unpublished/deleted?
76
- """
77
-
78
- entity = models.OneToOneField(
79
- PublishableEntity,
80
- on_delete=models.CASCADE,
81
- primary_key=True,
82
- )
83
- version = models.OneToOneField(
84
- PublishableEntityVersion,
85
- on_delete=models.RESTRICT,
86
- null=True,
87
- )
88
- publish_log_record = models.ForeignKey(
89
- PublishLogRecord,
90
- on_delete=models.RESTRICT,
91
- )
92
-
93
- class Meta:
94
- verbose_name = "Published Entity"
95
- verbose_name_plural = "Published Entities"