1 from datetime import date
2 from django.db import models
3 from django.db.models.signals import m2m_changed
4 from django.utils.translation import gettext_lazy as _
5 from django.dispatch import receiver
6 from wikidata.client import Client
7 from wikidata.datavalue import DatavalueError
10 class WikidataMixin(models.Model):
11 wikidata = models.CharField(
16 help_text=_('If you have a Wikidata ID, like "Q1337", enter it and save.'),
22 def save(self, **kwargs):
24 if self.wikidata and hasattr(self, "Wikidata"):
25 Wikidata = type(self).Wikidata
27 # Probably should getlist
28 entity = client.get(self.wikidata)
29 for attname in dir(Wikidata):
30 if attname.startswith("_"):
32 wd = getattr(Wikidata, attname)
34 model_field = self._meta.get_field(attname)
35 if isinstance(model_field, models.ManyToManyField):
36 if getattr(self, attname).all().exists():
39 if getattr(self, attname):
43 if wd == "description":
44 wdvalue = entity.description.get("pl", str(entity.description))
46 wdvalue = entity.label.get("pl", str(entity.label))
49 wdvalue = entity.get(client.get(wd))
50 except DatavalueError:
53 self.set_field_from_wikidata(attname, wdvalue)
55 kwargs.update(force_insert=False, force_update=True)
56 super().save(**kwargs)
58 def set_field_from_wikidata(self, attname, wdvalue):
61 # Find out what this model field is
62 model_field = self._meta.get_field(attname)
63 if isinstance(model_field, models.ForeignKey):
64 rel_model = model_field.related_model
65 if issubclass(rel_model, WikidataMixin):
66 # welp, we can try and find by WD identifier.
67 wdvalue, created = rel_model.objects.get_or_create(wikidata=wdvalue.id)
68 setattr(self, attname, wdvalue)
69 elif isinstance(model_field, models.ManyToManyField):
70 rel_model = model_field.related_model
71 if issubclass(rel_model, WikidataMixin):
72 wdvalue, created = rel_model.objects.get_or_create(wikidata=wdvalue.id)
73 getattr(self, attname).set([wdvalue])
75 # How to get original title?
76 if isinstance(wdvalue, date):
77 if isinstance(model_field, models.IntegerField):
78 wdvalue = wdvalue.year
79 elif not isinstance(wdvalue, str):
80 wdvalue = wdvalue.label.get("pl", str(wdvalue.label))
81 setattr(self, attname, wdvalue)
84 class WikidataAdminMixin:
85 def save_related(self, request, form, formsets, change):
86 super().save_related(request, form, formsets, change)