openedx-learning 0.5.1__py2.py3-none-any.whl → 0.6.1__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.
- openedx_learning/__init__.py +1 -1
- openedx_learning/contrib/media_server/views.py +2 -2
- openedx_learning/core/components/admin.py +22 -31
- openedx_learning/core/components/api.py +51 -47
- openedx_learning/core/components/migrations/0001_initial.py +12 -12
- openedx_learning/core/components/migrations/0002_alter_componentversioncontent_key.py +20 -0
- openedx_learning/core/components/models.py +37 -30
- openedx_learning/core/contents/admin.py +13 -20
- openedx_learning/core/contents/api.py +104 -94
- openedx_learning/core/contents/migrations/0001_initial.py +23 -30
- openedx_learning/core/contents/models.py +230 -149
- openedx_learning/core/publishing/migrations/0001_initial.py +2 -2
- openedx_learning/core/publishing/migrations/0002_alter_learningpackage_key_and_more.py +25 -0
- openedx_learning/core/publishing/models.py +41 -2
- openedx_learning/lib/fields.py +14 -2
- openedx_learning/lib/managers.py +6 -2
- {openedx_learning-0.5.1.dist-info → openedx_learning-0.6.1.dist-info}/METADATA +4 -4
- {openedx_learning-0.5.1.dist-info → openedx_learning-0.6.1.dist-info}/RECORD +24 -22
- openedx_tagging/core/tagging/data.py +1 -0
- openedx_tagging/core/tagging/models/base.py +36 -5
- openedx_tagging/core/tagging/rest_api/v1/serializers.py +1 -0
- {openedx_learning-0.5.1.dist-info → openedx_learning-0.6.1.dist-info}/LICENSE.txt +0 -0
- {openedx_learning-0.5.1.dist-info → openedx_learning-0.6.1.dist-info}/WHEEL +0 -0
- {openedx_learning-0.5.1.dist-info → openedx_learning-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
openedx_learning/__init__.py,sha256=
|
|
1
|
+
openedx_learning/__init__.py,sha256=4Akvu3WuVTtV-T_BQb8iO3zg_KBv_PDEc1owlfudTlQ,67
|
|
2
2
|
openedx_learning/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
openedx_learning/contrib/media_server/__init__.py,sha256=iYijWFCl5RNR9omSu22kMl49EfponoqXBqXr0HMp4QI,56
|
|
4
4
|
openedx_learning/contrib/media_server/apps.py,sha256=FPT0rsUFtPyhFpWKjSI1e_s58wU0IbDyaAW_66V6sY4,816
|
|
5
5
|
openedx_learning/contrib/media_server/urls.py,sha256=newNjV41sM9A9Oy_rgnZSXdkTFxSHiupIiAsVIGE2CE,365
|
|
6
|
-
openedx_learning/contrib/media_server/views.py,sha256=
|
|
6
|
+
openedx_learning/contrib/media_server/views.py,sha256=V-eq0SFi5815lkGdRz8dye4fF3dHzO5lVfm78gfG3mg,1537
|
|
7
7
|
openedx_learning/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
openedx_learning/core/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
openedx_learning/core/components/admin.py,sha256=
|
|
10
|
-
openedx_learning/core/components/api.py,sha256=
|
|
9
|
+
openedx_learning/core/components/admin.py,sha256=QE7e76C6X2V1AQPxQe6SayQPfCMmbs4RZPEPIGcvTWw,4672
|
|
10
|
+
openedx_learning/core/components/api.py,sha256=2ux1s9Bpfvs5sgTViHLagMb1IHpMo_vRR-MbrbXh0_U,12345
|
|
11
11
|
openedx_learning/core/components/apps.py,sha256=invLeAY0B-d_Ac9xu_b5ZWeb7v5NJe_-938BO9U2-jo,747
|
|
12
|
-
openedx_learning/core/components/models.py,sha256=
|
|
13
|
-
openedx_learning/core/components/migrations/0001_initial.py,sha256=
|
|
12
|
+
openedx_learning/core/components/models.py,sha256=duVLdkTFnM7ixsqXQPlvmqmgf32hYyXdeRw1W7MdOpg,13170
|
|
13
|
+
openedx_learning/core/components/migrations/0001_initial.py,sha256=446LkJSFeK8J_-l-bxakZ_BVx_CiJIllGcBYqWcEenA,4664
|
|
14
|
+
openedx_learning/core/components/migrations/0002_alter_componentversioncontent_key.py,sha256=98724dtucRjJCRyLt5p45qXYb2d6-ouVGp7PB6zTG6E,539
|
|
14
15
|
openedx_learning/core/components/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
16
|
openedx_learning/core/contents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
openedx_learning/core/contents/admin.py,sha256=
|
|
17
|
-
openedx_learning/core/contents/api.py,sha256=
|
|
17
|
+
openedx_learning/core/contents/admin.py,sha256=4ILH_cEiAXKUlfPVwJJZeh5yupgF3v7kf-xJ6ZTTFDE,1174
|
|
18
|
+
openedx_learning/core/contents/api.py,sha256=09159G0e_r7glDvi-G8c5k6ads2LmhmDLHnHeTSpotI,5553
|
|
18
19
|
openedx_learning/core/contents/apps.py,sha256=6O04ikajbc4FsSdzx7yEl0cdQpEHpK1LdE471vygdII,375
|
|
19
|
-
openedx_learning/core/contents/models.py,sha256=
|
|
20
|
-
openedx_learning/core/contents/migrations/0001_initial.py,sha256=
|
|
20
|
+
openedx_learning/core/contents/models.py,sha256=HInsxr3Bnl48_0fbdoDKnGmrpIxTFTpoQTUg6_opdB4,15143
|
|
21
|
+
openedx_learning/core/contents/migrations/0001_initial.py,sha256=FtOTmIGX2KHpjw-PHbfRjxkFEomI5CEDhNKCZ7IpFeE,3060
|
|
21
22
|
openedx_learning/core/contents/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
23
|
openedx_learning/core/publishing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
24
|
openedx_learning/core/publishing/admin.py,sha256=F-0QlVQmuovLIF258XK_vKJdOnn7lLa_0A5veE72TKc,4830
|
|
24
25
|
openedx_learning/core/publishing/api.py,sha256=pfBePrmP0jnU5YTt4x7qhT37RN02P95gw2-xQNA_e9A,14254
|
|
25
26
|
openedx_learning/core/publishing/apps.py,sha256=skY84raPW6gvrb5VPzhrLR2_gIHTUG67tMhSO7umVN4,379
|
|
26
27
|
openedx_learning/core/publishing/model_mixins.py,sha256=Y6hGh0MKVOx0dUyNL0YkLL9ErUnYI2Nv2ZGMhc3CMng,13412
|
|
27
|
-
openedx_learning/core/publishing/models.py,sha256=
|
|
28
|
-
openedx_learning/core/publishing/migrations/0001_initial.py,sha256=
|
|
28
|
+
openedx_learning/core/publishing/models.py,sha256=MGezxLoKFqHYnZccknqWyuNYrgiqu9eGDc4H9yIYzrg,20321
|
|
29
|
+
openedx_learning/core/publishing/migrations/0001_initial.py,sha256=wvekNV19YRSdxRmQaFnLSn_nCsQlHIucPDVMmgKf_OE,9272
|
|
30
|
+
openedx_learning/core/publishing/migrations/0002_alter_learningpackage_key_and_more.py,sha256=toI7qJhNukk6hirKfFx9EpqTpzF2O2Yq1VpFJusDn2M,806
|
|
29
31
|
openedx_learning/core/publishing/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
32
|
openedx_learning/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
33
|
openedx_learning/lib/admin_utils.py,sha256=5z9NrXxmT5j8azx9u1t0AgxV5PIDTc2jPyM5z5yW8cw,4021
|
|
32
34
|
openedx_learning/lib/cache.py,sha256=ppT36KiPLdsAF3GfZCF0IdiHodckd2gLiF1sNhjSJuk,958
|
|
33
35
|
openedx_learning/lib/collations.py,sha256=mMUXt6rnKoYOKTIVAVwiIQtWhaNsxRCfdeR25TPeK3U,4325
|
|
34
|
-
openedx_learning/lib/fields.py,sha256=
|
|
35
|
-
openedx_learning/lib/managers.py,sha256=
|
|
36
|
+
openedx_learning/lib/fields.py,sha256=eiGoXMPhRuq25EH2qf6BAODshAQE3DBVdIYAMIUAXW0,7522
|
|
37
|
+
openedx_learning/lib/managers.py,sha256=ofcUxHS2wsJSFP4CB7OCkN6JiWFxNlIyNh_VDgFtgug,1538
|
|
36
38
|
openedx_learning/lib/test_utils.py,sha256=g3KLuepIZbaDBCsaj9711YuqyUx7LD4gXDcfNC-mWdc,527
|
|
37
39
|
openedx_learning/lib/validators.py,sha256=98UldFhFxd77zF1VxzQcOPt0blh64gMZDv-d_uQ67mg,396
|
|
38
40
|
openedx_learning/rest_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -47,7 +49,7 @@ openedx_tagging/core/tagging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
47
49
|
openedx_tagging/core/tagging/admin.py,sha256=5mSTxlftMq5MVGzdE8xl3AcxgtfpnrKpXPNdvw7hAno,1075
|
|
48
50
|
openedx_tagging/core/tagging/api.py,sha256=jXmu2WPFDEiLKpz0OqVR8yo7NyKTo3omlRkytwa__L8,15758
|
|
49
51
|
openedx_tagging/core/tagging/apps.py,sha256=-gp0VYqX4XQzwjjd-G68Ev2Op0INLh9Byz5UOqF5_7k,345
|
|
50
|
-
openedx_tagging/core/tagging/data.py,sha256=
|
|
52
|
+
openedx_tagging/core/tagging/data.py,sha256=421EvmDzdM7H523dBVQk4J0W_UwTT4U5syqPRXUYK4g,1353
|
|
51
53
|
openedx_tagging/core/tagging/rules.py,sha256=UqIPPbOVA6FFF6uqLk0s5ORUczSYQt-a-S6Q_dB-RiE,6286
|
|
52
54
|
openedx_tagging/core/tagging/urls.py,sha256=-0Nzmh0mlF9-GgEuocwBdSJn6n8EINnxR4m4pmPou44,159
|
|
53
55
|
openedx_tagging/core/tagging/import_export/__init__.py,sha256=q5K4JalFQlJxAFUFyqhLY5zQtAskDnRM1H_aVuP_E3Q,83
|
|
@@ -78,7 +80,7 @@ openedx_tagging/core/tagging/migrations/0014_minor_fixes.py,sha256=46_F-el1UylSR
|
|
|
78
80
|
openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py,sha256=jhS-T8o2mwu61E7hPbjjE_6MPLKRPQFAVu7pJHZNRz4,1454
|
|
79
81
|
openedx_tagging/core/tagging/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
82
|
openedx_tagging/core/tagging/models/__init__.py,sha256=yYdOnthuc7EUdfEULtZgqRwn5Y4bbYQmJCjVZqR5GTM,236
|
|
81
|
-
openedx_tagging/core/tagging/models/base.py,sha256=
|
|
83
|
+
openedx_tagging/core/tagging/models/base.py,sha256=7I6pIbBOxev9abAX7bDvQ0Ac-DQMLbth0DJ7Kj6fTak,38291
|
|
82
84
|
openedx_tagging/core/tagging/models/import_export.py,sha256=cXsTk44CO6RZvmiMI5ERsyjuM-wYnJoORwCsGEj6OEc,4125
|
|
83
85
|
openedx_tagging/core/tagging/models/system_defined.py,sha256=_6LfvUZGEltvQMtm2OXy6TOLh3C8GnVTqtZDSAZW6K4,9062
|
|
84
86
|
openedx_tagging/core/tagging/models/utils.py,sha256=JD3ypABgEdx5lQBttFm0ByfgHJPuOQiJ8HYvUgAMA8g,1417
|
|
@@ -88,12 +90,12 @@ openedx_tagging/core/tagging/rest_api/urls.py,sha256=egXaRQv1EAgF04ThgVZBQuvLK1L
|
|
|
88
90
|
openedx_tagging/core/tagging/rest_api/utils.py,sha256=XZXixZ44vpNlxiyFplW8Lktyh_m1EfR3Y-tnyvA7acc,3620
|
|
89
91
|
openedx_tagging/core/tagging/rest_api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
92
|
openedx_tagging/core/tagging/rest_api/v1/permissions.py,sha256=FeSulmsFD7wAAuYpxFeGMZwgJW51d8K6bf6SQm6vbgA,2131
|
|
91
|
-
openedx_tagging/core/tagging/rest_api/v1/serializers.py,sha256=
|
|
93
|
+
openedx_tagging/core/tagging/rest_api/v1/serializers.py,sha256=I9jk3x3wPIeV_XCyC4uNTeqllumXpcQLVD0rdy_YNH8,13088
|
|
92
94
|
openedx_tagging/core/tagging/rest_api/v1/urls.py,sha256=dNUKCtUCx_YzrwlbEbpDfjGVQbb2QdJ1VuJCkladj6E,752
|
|
93
95
|
openedx_tagging/core/tagging/rest_api/v1/views.py,sha256=opPY8xwbOupUaLnX0ovCV-oJ06l-d_qV8CgT47-m-Dc,34358
|
|
94
96
|
openedx_tagging/core/tagging/rest_api/v1/views_import.py,sha256=kbHUPe5A6WaaJ3J1lFIcYCt876ecLNQfd19m7YYub6c,1470
|
|
95
|
-
openedx_learning-0.
|
|
96
|
-
openedx_learning-0.
|
|
97
|
-
openedx_learning-0.
|
|
98
|
-
openedx_learning-0.
|
|
99
|
-
openedx_learning-0.
|
|
97
|
+
openedx_learning-0.6.1.dist-info/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
|
|
98
|
+
openedx_learning-0.6.1.dist-info/METADATA,sha256=yw2xbOghDZ_i09kmUY-TqCnVX3gTYc0KP164ZDzis0E,8758
|
|
99
|
+
openedx_learning-0.6.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110
|
|
100
|
+
openedx_learning-0.6.1.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
|
|
101
|
+
openedx_learning-0.6.1.dist-info/RECORD,,
|
|
@@ -171,6 +171,18 @@ class Tag(models.Model):
|
|
|
171
171
|
return self.taxonomy.tag_set.filter(parent=self).count()
|
|
172
172
|
return 0
|
|
173
173
|
|
|
174
|
+
@cached_property
|
|
175
|
+
def descendant_count(self) -> int:
|
|
176
|
+
"""
|
|
177
|
+
How many descendant tags this tag has in the taxonomy.
|
|
178
|
+
"""
|
|
179
|
+
if self.taxonomy and not self.taxonomy.allow_free_text:
|
|
180
|
+
return self.taxonomy.tag_set.filter(
|
|
181
|
+
Q(parent__parent=self) |
|
|
182
|
+
Q(parent__parent__parent=self)
|
|
183
|
+
).count() + self.child_count
|
|
184
|
+
return 0
|
|
185
|
+
|
|
174
186
|
def clean(self):
|
|
175
187
|
"""
|
|
176
188
|
Validate this tag before saving
|
|
@@ -436,6 +448,7 @@ class Taxonomy(models.Model):
|
|
|
436
448
|
qs = qs.annotate(
|
|
437
449
|
depth=Value(0),
|
|
438
450
|
child_count=Value(0),
|
|
451
|
+
descendant_count=Value(0),
|
|
439
452
|
external_id=Value(None, output_field=models.CharField()),
|
|
440
453
|
parent_value=Value(None, output_field=models.CharField()),
|
|
441
454
|
_id=Value(None, output_field=models.CharField()),
|
|
@@ -467,12 +480,16 @@ class Taxonomy(models.Model):
|
|
|
467
480
|
else:
|
|
468
481
|
qs = self.tag_set.filter(parent=None).annotate(depth=Value(0))
|
|
469
482
|
qs = qs.annotate(parent_value=Value(None, output_field=models.CharField()))
|
|
470
|
-
qs = qs.annotate(child_count=models.Count("children"))
|
|
483
|
+
qs = qs.annotate(child_count=models.Count("children", distinct=True))
|
|
484
|
+
qs = qs.annotate(grandchild_count=models.Count("children__children", distinct=True))
|
|
485
|
+
qs = qs.annotate(great_grandchild_count=models.Count("children__children__children"))
|
|
486
|
+
qs = qs.annotate(descendant_count=F("child_count") + F("grandchild_count") + F("great_grandchild_count"))
|
|
471
487
|
# Filter by search term:
|
|
472
488
|
if search_term:
|
|
473
489
|
qs = qs.filter(value__icontains=search_term)
|
|
474
490
|
qs = qs.annotate(_id=F("id")) # ID has an underscore to encourage use of 'value' rather than this internal ID
|
|
475
|
-
qs = qs.values("value", "child_count", "depth", "parent_value", "external_id", "_id")
|
|
491
|
+
qs = qs.values("value", "child_count", "descendant_count", "depth", "parent_value", "external_id", "_id")
|
|
492
|
+
qs = qs.order_by("value")
|
|
476
493
|
if include_counts:
|
|
477
494
|
# We need to include the count of how many times this tag is used to tag objects.
|
|
478
495
|
# You'd think we could just use:
|
|
@@ -524,14 +541,27 @@ class Taxonomy(models.Model):
|
|
|
524
541
|
if pk is not None:
|
|
525
542
|
matching_ids.append(pk)
|
|
526
543
|
qs = qs.filter(pk__in=matching_ids)
|
|
527
|
-
qs = qs.annotate(
|
|
544
|
+
qs = qs.annotate(
|
|
545
|
+
child_count=models.Count("children", filter=Q(children__pk__in=matching_ids), distinct=True),
|
|
546
|
+
grandchild_count=models.Count(
|
|
547
|
+
"children__children", filter=Q(children__children__pk__in=matching_ids), distinct=True,
|
|
548
|
+
),
|
|
549
|
+
great_grandchild_count=models.Count(
|
|
550
|
+
"children__children__children",
|
|
551
|
+
filter=Q(children__children__children__pk__in=matching_ids),
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
qs = qs.annotate(descendant_count=F("child_count") + F("grandchild_count") + F("great_grandchild_count"))
|
|
528
555
|
elif excluded_values:
|
|
529
556
|
raise NotImplementedError("Using excluded_values without search_term is not currently supported.")
|
|
530
557
|
# We could implement this in the future but I'd prefer to get rid of the "excluded_values" API altogether.
|
|
531
558
|
# It remains to be seen if it's useful to do that on the backend, or if we can do it better/simpler on the
|
|
532
559
|
# frontend.
|
|
533
560
|
else:
|
|
534
|
-
qs = qs.annotate(child_count=models.Count("children"))
|
|
561
|
+
qs = qs.annotate(child_count=models.Count("children", distinct=True))
|
|
562
|
+
qs = qs.annotate(grandchild_count=models.Count("children__children", distinct=True))
|
|
563
|
+
qs = qs.annotate(great_grandchild_count=models.Count("children__children__children"))
|
|
564
|
+
qs = qs.annotate(descendant_count=F("child_count") + F("grandchild_count") + F("great_grandchild_count"))
|
|
535
565
|
|
|
536
566
|
# Add the "depth" to each tag:
|
|
537
567
|
qs = Tag.annotate_depth(qs)
|
|
@@ -550,7 +580,8 @@ class Taxonomy(models.Model):
|
|
|
550
580
|
# Add the parent value
|
|
551
581
|
qs = qs.annotate(parent_value=F("parent__value"))
|
|
552
582
|
qs = qs.annotate(_id=F("id")) # ID has an underscore to encourage use of 'value' rather than this internal ID
|
|
553
|
-
qs = qs.values("value", "child_count", "depth", "parent_value", "external_id", "_id")
|
|
583
|
+
qs = qs.values("value", "child_count", "descendant_count", "depth", "parent_value", "external_id", "_id")
|
|
584
|
+
qs = qs.order_by("sort_key")
|
|
554
585
|
if include_counts:
|
|
555
586
|
# Including the counts is a bit tricky; see the comment above in _get_filtered_tags_one_level()
|
|
556
587
|
obj_tags = ObjectTag.objects.filter(tag_id=models.OuterRef("pk")).order_by().annotate(
|
|
@@ -210,6 +210,7 @@ class TagDataSerializer(UserPermissionsSerializerMixin, serializers.Serializer):
|
|
|
210
210
|
value = serializers.CharField()
|
|
211
211
|
external_id = serializers.CharField(allow_null=True)
|
|
212
212
|
child_count = serializers.IntegerField()
|
|
213
|
+
descendant_count = serializers.IntegerField()
|
|
213
214
|
depth = serializers.IntegerField()
|
|
214
215
|
parent_value = serializers.CharField(allow_null=True)
|
|
215
216
|
usage_count = serializers.IntegerField(required=False)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|