1 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 
   2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 
   4 from datetime import date
 
   5 from django.db import models
 
   6 from django.db.models.signals import m2m_changed
 
   7 from django.utils.html import format_html
 
   8 from django.utils.translation import gettext_lazy as _
 
   9 from django.dispatch import receiver
 
  10 from wikidata.client import Client
 
  11 from wikidata.datavalue import DatavalueError
 
  14 class WikidataMixin(models.Model):
 
  15     wikidata = models.CharField(
 
  18         help_text=_('If you have a Wikidata ID, like "Q1337", enter it and save.'),
 
  24     def wikidata_populate(self, client, entity, attname, wd):
 
  25         model_field = self._meta.get_field(attname)
 
  26         if isinstance(model_field, models.ManyToManyField):
 
  27             if getattr(self, attname).all().exists():
 
  30             if getattr(self, attname):
 
  34         if wd == "description":
 
  35             wdvalue = entity.description.get("pl", str(entity.description))
 
  37             wdvalue = entity.label.get("pl", str(entity.label))
 
  40                 wdvalue = entity.get(client.get(wd))
 
  41             except DatavalueError:
 
  44         self.set_field_from_wikidata(attname, wdvalue)
 
  46     def save(self, **kwargs):
 
  48         if self.wikidata and hasattr(self, "Wikidata"):
 
  49             Wikidata = type(self).Wikidata
 
  51             # Probably should getlist
 
  52             entity = client.get(self.wikidata)
 
  53             for attname in dir(Wikidata):
 
  54                 if attname.startswith("_"):
 
  56                 wd = getattr(Wikidata, attname)
 
  58                 self.wikidata_populate(client, entity, attname, wd)
 
  59             if hasattr(Wikidata, '_supplement'):
 
  60                 for attname, wd in Wikidata._supplement(self):
 
  61                     self.wikidata_populate(client, entity, attname, wd)
 
  64         kwargs.update(force_insert=False, force_update=True)
 
  65         super().save(**kwargs)
 
  67     def set_field_from_wikidata(self, attname, wdvalue):
 
  70         # Find out what this model field is
 
  71         model_field = self._meta.get_field(attname)
 
  72         if isinstance(model_field, models.ForeignKey):
 
  73             rel_model = model_field.related_model
 
  74             if issubclass(rel_model, WikidataMixin):
 
  75                 # welp, we can try and find by WD identifier.
 
  76                 wdvalue, created = rel_model.objects.get_or_create(wikidata=wdvalue.id)
 
  77                 setattr(self, attname, wdvalue)
 
  78         elif isinstance(model_field, models.ManyToManyField):
 
  79             rel_model = model_field.related_model
 
  80             if issubclass(rel_model, WikidataMixin):
 
  81                 wdvalue, created = rel_model.objects.get_or_create(wikidata=wdvalue.id)
 
  82                 getattr(self, attname).set([wdvalue])
 
  84             # How to get original title?
 
  85             if isinstance(wdvalue, date):
 
  86                 if isinstance(model_field, models.IntegerField):
 
  87                     wdvalue = wdvalue.year
 
  88             elif not isinstance(wdvalue, str):
 
  89                 wdvalue = wdvalue.label.get("pl", str(wdvalue.label))
 
  90             setattr(self, attname, wdvalue)
 
  92     def wikidata_link(self):
 
  95                 '<a href="https://www.wikidata.org/wiki/{wd}" target="_blank">{wd}</a>',
 
 101     wikidata_link.admin_order_field = "wikidata"
 
 104 class WikidataAdminMixin:
 
 105     def save_related(self, request, form, formsets, change):
 
 106         super().save_related(request, form, formsets, change)