From 6c9dd620f39279c7f55b4437b931130d7f2fd210 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 5 Jun 2023 17:22:34 -0400 Subject: [PATCH] use json format for crew & actors --- catalog/performance/models.py | 64 +++++++++++++++++--- catalog/performance/tests.py | 24 +++++++- catalog/sites/douban_drama.py | 14 ++++- catalog/templates/performance.html | 10 +-- catalog/templates/performanceproduction.html | 5 +- catalog/views.py | 9 ++- common/templates/400.html | 7 ++- journal/templates/list_item_performance.html | 3 +- 8 files changed, 113 insertions(+), 23 deletions(-) diff --git a/catalog/performance/models.py b/catalog/performance/models.py index c39b793d..61b7be5d 100644 --- a/catalog/performance/models.py +++ b/catalog/performance/models.py @@ -1,8 +1,35 @@ -from catalog.common import * +from functools import cached_property from django.utils.translation import gettext_lazy as _ from django.db import models +from catalog.common import * from catalog.common.utils import DEFAULT_ITEM_COVER -from functools import cached_property + + +_CREW_SCHEMA = { + "type": "list", + "items": { + "type": "dict", + "keys": { + "name": {"type": "string", "title": _("名字")}, + "role": {"type": "string", "title": _("职能")}, + }, + "required": ["role", "name"], + }, + "uniqueItems": True, +} + +_ACTOR_SCHEMA = { + "type": "list", + "items": { + "type": "dict", + "keys": { + "name": {"type": "string", "title": _("名字"), "placeholder": _("演员名字,必填")}, + "role": {"type": "string", "title": _("角色"), "placeholder": _("也可不填写")}, + }, + "required": ["name"], + }, + "uniqueItems": True, +} class Performance(Item): @@ -69,8 +96,15 @@ class Performance(Item): blank=True, default=list, ) - performer = jsondata.ArrayField( + actor = jsondata.JSONField( verbose_name=_("演员"), + null=False, + blank=True, + default=list, + schema=_ACTOR_SCHEMA, + ) + performer = jsondata.ArrayField( + verbose_name=_("表演者"), base_field=models.CharField(blank=True, default="", max_length=500), null=False, blank=True, @@ -83,12 +117,12 @@ class Performance(Item): blank=True, default=list, ) - crew = jsondata.ArrayField( + crew = jsondata.JSONField( verbose_name=_("其他演职人员和团体"), - base_field=models.CharField(blank=True, default="", max_length=500), null=False, blank=True, default=list, + schema=_CREW_SCHEMA, ) location = jsondata.ArrayField( verbose_name=_("剧场空间"), @@ -98,7 +132,10 @@ class Performance(Item): default=list, ) opening_date = jsondata.CharField( - verbose_name=_("首演日期"), max_length=100, null=True, blank=True + verbose_name=_("首演日期"), + max_length=100, + null=True, + blank=True, ) closing_date = jsondata.CharField( verbose_name=_("结束日期"), max_length=100, null=True, blank=True @@ -122,6 +159,7 @@ class Performance(Item): "orig_creator", "composer", "choreographer", + "actor", "performer", "crew", "official_site", @@ -196,8 +234,15 @@ class PerformanceProduction(Item): blank=True, default=list, ) - performer = jsondata.ArrayField( + actor = jsondata.JSONField( verbose_name=_("演员"), + null=False, + blank=True, + default=list, + schema=_ACTOR_SCHEMA, + ) + performer = jsondata.ArrayField( + verbose_name=_("表演者"), base_field=models.CharField(blank=True, default="", max_length=500), null=False, blank=True, @@ -210,12 +255,12 @@ class PerformanceProduction(Item): blank=True, default=list, ) - crew = jsondata.ArrayField( + crew = jsondata.JSONField( verbose_name=_("其他演职人员和团体"), - base_field=models.CharField(blank=True, default="", max_length=500), null=False, blank=True, default=list, + schema=_CREW_SCHEMA, ) location = jsondata.ArrayField( verbose_name=_("剧场空间"), @@ -248,6 +293,7 @@ class PerformanceProduction(Item): "orig_creator", "composer", "choreographer", + "actor", "performer", "crew", "official_site", diff --git a/catalog/performance/tests.py b/catalog/performance/tests.py index cf72bf1c..df1737bb 100644 --- a/catalog/performance/tests.py +++ b/catalog/performance/tests.py @@ -70,11 +70,31 @@ class DoubanDramaTestCase(TestCase): # ) self.assertEqual(item.director, ["小池修一郎", "小池 修一郎", "石丸さち子"]) self.assertEqual(item.playwright, ["小池修一郎", "Baroness Orczy(原作)", "小池 修一郎"]) - self.assertEqual(item.performer, ["安蘭けい", "柚希礼音", "遠野あすか", "霧矢大夢", "龍真咲"]) + self.assertEqual( + item.actor, + [ + {"name": "安蘭けい", "role": ""}, + {"name": "柚希礼音", "role": ""}, + {"name": "遠野あすか", "role": ""}, + {"name": "霧矢大夢", "role": ""}, + {"name": "龍真咲", "role": ""}, + ], + ) self.assertEqual(len(resource.related_resources), 4) crawl_related_resources_task(resource.id) # force the async job to run now productions = list(item.productions.all().order_by("title")) self.assertEqual(len(productions), 4) + self.assertEqual( + productions[3].actor, + [ + {"name": "石丸幹二", "role": "パーシー・ブレイクニー"}, + {"name": "石井一孝", "role": "ショーヴラン"}, + {"name": "安蘭けい", "role": "マルグリット・サン・ジュスト"}, + {"name": "上原理生", "role": ""}, + {"name": "泉見洋平", "role": ""}, + {"name": "松下洸平", "role": "アルマン"}, + ], + ) self.assertEqual(productions[0].opening_date, "2008-06-20") self.assertEqual(productions[0].closing_date, "2008-08-04") self.assertEqual(productions[2].opening_date, "2017-03-10") @@ -82,7 +102,7 @@ class DoubanDramaTestCase(TestCase): self.assertEqual(productions[3].opening_date, "2017-11-13") self.assertEqual(productions[3].closing_date, None) self.assertEqual(productions[3].title, "ミュージカル(2017年)版") - self.assertEqual(len(productions[3].performer), 6) + self.assertEqual(len(productions[3].actor), 6) self.assertEqual(productions[3].language, ["日语"]) self.assertEqual(productions[3].opening_date, "2017-11-13") self.assertEqual(productions[3].location, ["梅田芸術劇場メインホール"]) diff --git a/catalog/sites/douban_drama.py b/catalog/sites/douban_drama.py index 1d36d052..d59319ef 100644 --- a/catalog/sites/douban_drama.py +++ b/catalog/sites/douban_drama.py @@ -63,7 +63,7 @@ class DoubanDramaVersion(AbstractSite): "title": title, "director": [x.strip() for x in h.xpath(q.format("导演"))], "playwright": [x.strip() for x in h.xpath(q.format("编剧"))], - "performer": [x.strip() for x in h.xpath(q.format("主演"))], + # "actor": [x.strip() for x in h.xpath(q.format("主演"))], "composer": [x.strip() for x in h.xpath(q.format("作曲"))], "language": [x.strip() for x in h.xpath(q2.format("语言"))], "opening_date": " ".join(h.xpath(q2.format("演出日期"))).strip(), @@ -76,6 +76,14 @@ class DoubanDramaVersion(AbstractSite): if l > 3: data["opening_date"] = "-".join(d[:3]) data["closing_date"] = "-".join(d[0 : 6 - l] + d[3:l]) + actor_elem = h.xpath(p + "//dt[text()='主演:']/following-sibling::dd[1]/a") + data["actor"] = [] + for e in actor_elem: + n = "".join(e.xpath("span/text()")).strip() + t = "".join(e.xpath("following-sibling::text()[1]")).strip() + t = re.sub(r"^[\s\(饰]*(.+)\)[\s\/]*$", r"\1", t).strip() + t = t if t != "/" else "" + data["actor"].append({"name": n, "role": t}) img_url_elem = h.xpath("//img[@itemprop='image']/@src") data["cover_image_url"] = img_url_elem[0].strip() if img_url_elem else None pd = ResourceContent(metadata=data) @@ -184,8 +192,8 @@ class DoubanDrama(AbstractSite): "//div[@class='meta']/dl//dt[text()='编剧:']/following-sibling::dd/a[@itemprop='author']//text()" ) ] - data["performer"] = [ - s.strip() + data["actor"] = [ + {"name": s.strip(), "role": ""} for s in h.xpath( "//div[@class='meta']/dl//dt[text()='主演:']/following-sibling::dd/a[@itemprop='actor']//text()" ) diff --git a/catalog/templates/performance.html b/catalog/templates/performance.html index f6b5d7c1..e2e183ae 100644 --- a/catalog/templates/performance.html +++ b/catalog/templates/performance.html @@ -25,10 +25,11 @@
{% include '_people.html' with people=item.orig_creator role='原作' max=5 %}
{% include '_people.html' with people=item.director role='导演' max=5 %}
{% include '_people.html' with people=item.playwright role='编剧' max=5 %}
-
{% include '_people.html' with people=item.performer role='演员' max=10 %}
+
{% include '_crew.html' with people=item.actor role='演员' max=10 %}
+
{% include '_people.html' with people=item.performer role='表演者' max=10 %}
{% include '_people.html' with people=item.composer role='作曲' max=5 %}
{% include '_people.html' with people=item.choreographer role='编舞' max=5 %}
-
{% include '_people.html' with people=item.crew role='演职人员' max=10 %}
+
{% include '_crew.html' with people=item.crew role='演职人员' max=10 %}
{% if item.official_site %} {% trans '官方网站' %}: {{ item.official_site|urlizetrunc:24 }} @@ -58,10 +59,11 @@ {% include '_people.html' with people=prod.orig_creator role='原作' max=2 %} {% include '_people.html' with people=prod.director role='导演' max=2 %} {% include '_people.html' with people=prod.playwright role='编剧' max=2 %} - {% include '_people.html' with people=prod.performer role='演员' max=5 %} + {% include '_crew.html' with people=prod.actor role='演员' max=5 %} + {% include '_people.html' with people=prod.performer role='表演者' max=5 %} {% include '_people.html' with people=prod.composer role='作曲' max=2 %} {% include '_people.html' with people=prod.choreographer role='编舞' max=2 %} - {% include '_people.html' with people=prod.crew role='演职人员' max=5 %} + {% include '_crew.html' with people=prod.crew role='演职人员' max=5 %}
{% endfor %} diff --git a/catalog/templates/performanceproduction.html b/catalog/templates/performanceproduction.html index 383713be..6abcdea6 100644 --- a/catalog/templates/performanceproduction.html +++ b/catalog/templates/performanceproduction.html @@ -30,10 +30,11 @@
{% include '_people.html' with people=item.orig_creator role='原作' max=5 %}
{% include '_people.html' with people=item.director role='导演' max=5 %}
{% include '_people.html' with people=item.playwright role='编剧' max=5 %}
-
{% include '_people.html' with people=item.performer role='演员' max=10 %}
+
{% include '_crew.html' with people=item.actor role='演员' max=50 %}
+
{% include '_people.html' with people=item.performer role='表演者' max=50 %}
{% include '_people.html' with people=item.composer role='作曲' max=5 %}
{% include '_people.html' with people=item.choreographer role='编舞' max=5 %}
-
{% include '_people.html' with people=item.crew role='演职人员' max=10 %}
+
{% include '_crew.html' with people=item.crew role='演职人员' max=50 %}
{% if item.official_site %} {% trans '官方网站' %}: {{ item.official_site|urlizetrunc:24 }} diff --git a/catalog/views.py b/catalog/views.py index 0fa04725..84b4c49a 100644 --- a/catalog/views.py +++ b/catalog/views.py @@ -183,7 +183,14 @@ def edit(request, item_path, item_uuid): form.instance.save() return redirect(form.instance.url) else: - raise BadRequest(form.errors) + e = form.errors + e.additonal_detail = [] + for f, v in e.as_data().items(): + for validation_error in v: + if hasattr(validation_error, "error_map"): + for f2, v2 in validation_error.error_map.items(): + e.additonal_detail.append(f"{f}§{f2}: {'; '.join(v2)}") + raise BadRequest(e) else: raise BadRequest() diff --git a/common/templates/400.html b/common/templates/400.html index 6a3ab86a..ac15ee85 100644 --- a/common/templates/400.html +++ b/common/templates/400.html @@ -21,8 +21,13 @@

🤦🏻 无效的请求

- {{ exception }} 您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。 +
+ {{ exception }} + {% if exception.additonal_detail %} + {% for e in exception.additonal_detail %}

{{ e }}

{% endfor %} + {% endif %} +
{% include "partial/_footer.html" %} diff --git a/journal/templates/list_item_performance.html b/journal/templates/list_item_performance.html index f8e24786..86f4774d 100644 --- a/journal/templates/list_item_performance.html +++ b/journal/templates/list_item_performance.html @@ -14,7 +14,8 @@
{% include '_people.html' with people=item.other_title role='又名' max=2 %}
{% include '_people.html' with people=item.director role='导演' max=2 %}
{% include '_people.html' with people=item.playwright role='编剧' max=2 %}
-
{% include '_people.html' with people=item.performer role='演员' max=5 %}
+
{% include '_people.html' with people=item.actor role='演员' max=5 %}
+
{% include '_people.html' with people=item.performer role='表演者' max=5 %}
{% include '_people.html' with people=item.composer role='作曲' max=2 %}
{% include '_people.html' with people=item.choreographer role='编舞' max=2 %}
{% include '_people.html' with people=item.crew role='演职人员' max=2 %}