From: Radek Czajka Date: Mon, 5 Aug 2019 12:42:55 +0000 (+0200) Subject: Remove obsolete jsonfield dependency. X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/c2e8051452fa55db096553cbe5ae622fc363d481?ds=inline Remove obsolete jsonfield dependency. --- diff --git a/requirements/requirements.txt b/requirements/requirements.txt index a5f04677f..b8e46befa 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -7,7 +7,6 @@ django-pipeline==1.6.13 jsmin fnp-django-pagination==2.2.3 django-maintenancemode==0.11.3 -jsonfield==2.0.2 django-picklefield==1.1.0 django-modeltranslation==0.13 django-allauth==0.39 diff --git a/src/catalogue/feeds.py b/src/catalogue/feeds.py index f0305e76f..82b0a75fd 100644 --- a/src/catalogue/feeds.py +++ b/src/catalogue/feeds.py @@ -55,10 +55,11 @@ class AudiobookFeed(Feed): def item_description(self, item): lines = [] - artist = item.extra_info.get('artist_name', None) + extra_info = item.get_extra_info_json() + artist = extra_info.get('artist_name', None) if artist is not None: lines.append(u'Czyta: %s' % artist) - director = item.extra_info.get('director_name', None) + director = extra_info.get('director_name', None) if director is not None: lines.append(u'Reżyseria: %s' % director) return u'
\n'.join(lines) diff --git a/src/catalogue/fixtures/test-books.yaml b/src/catalogue/fixtures/test-books.yaml index fcb3617c5..6c24400b5 100644 --- a/src/catalogue/fixtures/test-books.yaml +++ b/src/catalogue/fixtures/test-books.yaml @@ -129,7 +129,7 @@ name: Parent Audiobook file: mp3/parent.mp3 uploaded_at: "1970-01-03 0:0Z" - extra_info: {"director_name": "Director", "artist_name": "Artist"} + extra_info: '{"director_name": "Director", "artist_name": "Artist"}' - model: catalogue.bookmedia fields: book: 1 diff --git a/src/catalogue/management/commands/checkcovers.py b/src/catalogue/management/commands/checkcovers.py index 66a69c78f..db9fc4c47 100644 --- a/src/catalogue/management/commands/checkcovers.py +++ b/src/catalogue/management/commands/checkcovers.py @@ -10,7 +10,7 @@ from catalogue import app_settings def ancestor_has_cover(book): while book.parent: book = book.parent - if book.extra_info.get('cover_url'): + if book.get_extra_info_json().get('cover_url'): return True return False @@ -54,7 +54,7 @@ class Command(BaseCommand): with transaction.atomic(): for book in Book.objects.all().order_by('slug').iterator(): - extra_info = book.extra_info + extra_info = book.get_extra_info_json() if not extra_info.get('cover_url'): if ancestor_has_cover(book): with_ancestral_cover.append(book) @@ -100,9 +100,10 @@ Bad licenses used: %s (%d covers without license). for book in no_license: print() print(full_url(book)) - print(book.extra_info.get('cover_by')) - print(book.extra_info.get('cover_source')) - print(book.extra_info.get('cover_url')) + extra_info = book.get_extra_info_json() + print(extra_info.get('cover_by')) + print(extra_info.get('cover_source')) + print(extra_info.get('cover_url')) if not_redakcja: print() @@ -111,9 +112,10 @@ Bad licenses used: %s (%d covers without license). for book in not_redakcja: print() print(full_url(book)) - print(book.extra_info.get('cover_by')) - print(book.extra_info.get('cover_source')) - print(book.extra_info.get('cover_url')) + extra_info = book.get_extra_info_json() + print(extra_info.get('cover_by')) + print(extra_info.get('cover_source')) + print(extra_info.get('cover_url')) if without_cover: print() diff --git a/src/catalogue/management/commands/report_dead_links.py b/src/catalogue/management/commands/report_dead_links.py index ddcc2168f..5f193c415 100644 --- a/src/catalogue/management/commands/report_dead_links.py +++ b/src/catalogue/management/commands/report_dead_links.py @@ -21,7 +21,7 @@ class Command(BaseCommand): Book, [ ('wiki_link', lambda b: b.wiki_link), - ('źródło', lambda b: b.extra_info.get('source_url')), + ('źródło', lambda b: b.get_extra_info_json().get('source_url')), ], 'admin:catalogue_book_change' ), @@ -29,7 +29,7 @@ class Command(BaseCommand): Picture, [ ('wiki_link', lambda p: p.wiki_link), - ('źródło', lambda p: p.extra_info.get('source_url')), + ('źródło', lambda p: p.get_extra_info_json().get('source_url')), ], 'admin:pictures_picture_change' ) @@ -51,8 +51,8 @@ class Command(BaseCommand): print( ('Administracja: https://%s%s' % (domain, reverse(admin_name, args=[obj.pk]))) .encode('utf-8')) - if obj.extra_info.get('about'): - print(('Redakcja: %s' % (obj.extra_info.get('about'),)).encode('utf-8')) + if obj.get_extra_info_json().get('about'): + print(('Redakcja: %s' % (obj.get_extra_info_json().get('about'),)).encode('utf-8')) print((' %s (%s): %s' % (name, getattr(e, 'code', 'błąd'), url)).encode('utf-8')) if not clean: print() diff --git a/src/catalogue/migrations/0001_initial.py b/src/catalogue/migrations/0001_initial.py index 987d81178..3acfad969 100644 --- a/src/catalogue/migrations/0001_initial.py +++ b/src/catalogue/migrations/0001_initial.py @@ -1,7 +1,6 @@ from django.db import models, migrations import django.db.models.deletion import fnpdjango.storage -import jsonfield.fields import catalogue.fields import catalogue.models.bookmedia from django.conf import settings @@ -30,12 +29,12 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='creation date', db_index=True)), ('changed_at', models.DateTimeField(auto_now=True, verbose_name='creation date', db_index=True)), ('parent_number', models.IntegerField(default=0, verbose_name='Parent number')), - ('extra_info', jsonfield.fields.JSONField(default={}, verbose_name='Additional information')), + ('extra_info', models.TextField(default='{}', verbose_name='Additional information')), ('gazeta_link', models.CharField(max_length=240, blank=True)), ('wiki_link', models.CharField(max_length=240, blank=True)), ('cover', catalogue.fields.EbookField('cover', upload_to=catalogue.models.book._cover_upload_to, storage=fnpdjango.storage.BofhFileSystemStorage(), max_length=255, blank=True, null=True, verbose_name='cover')), ('cover_thumb', catalogue.fields.EbookField('cover_thumb', max_length=255, upload_to=catalogue.models.book._cover_thumb_upload_to, null=True, verbose_name='cover thumbnail', blank=True)), - ('_related_info', jsonfield.fields.JSONField(null=True, editable=False, blank=True)), + ('_related_info', models.TextField(null=True, editable=False, blank=True)), ('txt_file', catalogue.fields.EbookField('txt', default='', storage=fnpdjango.storage.BofhFileSystemStorage(), upload_to=catalogue.models.book._txt_upload_to, max_length=255, blank=True, verbose_name='TXT file')), ('fb2_file', catalogue.fields.EbookField('fb2', default='', storage=fnpdjango.storage.BofhFileSystemStorage(), upload_to=catalogue.models.book._fb2_upload_to, max_length=255, blank=True, verbose_name='FB2 file')), ('pdf_file', catalogue.fields.EbookField('pdf', default='', storage=fnpdjango.storage.BofhFileSystemStorage(), upload_to=catalogue.models.book._pdf_upload_to, max_length=255, blank=True, verbose_name='PDF file')), @@ -60,7 +59,7 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=512, verbose_name='name')), ('file', catalogue.fields.OverwritingFileField(upload_to=catalogue.models.bookmedia._file_upload_to, max_length=600, verbose_name='XML file')), ('uploaded_at', models.DateTimeField(auto_now_add=True, verbose_name='creation date', db_index=True)), - ('extra_info', jsonfield.fields.JSONField(default={}, verbose_name='Additional information', editable=False)), + ('extra_info', models.TextField(default='{}', verbose_name='Additional information', editable=False)), ('source_sha1', models.CharField(max_length=40, null=True, editable=False, blank=True)), ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='media', to='catalogue.Book')), ], diff --git a/src/catalogue/migrations/0008_auto_20151221_1225.py b/src/catalogue/migrations/0008_auto_20151221_1225.py index c7f0aa773..d8e9af1cf 100644 --- a/src/catalogue/migrations/0008_auto_20151221_1225.py +++ b/src/catalogue/migrations/0008_auto_20151221_1225.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from django.db import migrations, models -import jsonfield.fields import catalogue.fields import catalogue.models.bookmedia @@ -40,7 +39,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='book', name='extra_info', - field=jsonfield.fields.JSONField(default={}, verbose_name='extra information'), + field=models.TextField(default='{}', verbose_name='extra information'), ), migrations.AlterField( model_name='book', @@ -65,7 +64,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='bookmedia', name='extra_info', - field=jsonfield.fields.JSONField(default={}, verbose_name='extra information', editable=False), + field=models.TextField(default='{}', verbose_name='extra information', editable=False), ), migrations.AlterField( model_name='bookmedia', diff --git a/src/catalogue/migrations/0016_auto_20171031_1232.py b/src/catalogue/migrations/0016_auto_20171031_1232.py index 5892a2991..f606c13d9 100644 --- a/src/catalogue/migrations/0016_auto_20171031_1232.py +++ b/src/catalogue/migrations/0016_auto_20171031_1232.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models @@ -12,7 +9,7 @@ def refresh_books(apps, schema_editor): book.cached_author = ', '.join( TagRelation.objects.filter(content_type__model='book', object_id=book.id, tag__category='author') .values_list('tag__name', flat=True)) - book.has_audience = 'audience' in book.extra_info + book.has_audience = 'audience' in book.get_extra_info_json() book.save() diff --git a/src/catalogue/models/book.py b/src/catalogue/models/book.py index af4c9410a..033febf34 100644 --- a/src/catalogue/models/book.py +++ b/src/catalogue/models/book.py @@ -2,6 +2,7 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from collections import OrderedDict +import json from datetime import date, timedelta from random import randint import os.path @@ -14,7 +15,6 @@ from django.contrib.contenttypes.fields import GenericRelation from django.urls import reverse from django.utils.translation import ugettext_lazy as _, get_language from django.utils.deconstruct import deconstructible -import jsonfield from fnpdjango.storage import BofhFileSystemStorage from librarian.cover import WLCover @@ -65,7 +65,7 @@ class Book(models.Model): created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True) changed_at = models.DateTimeField(_('change date'), auto_now=True, db_index=True) parent_number = models.IntegerField(_('parent number'), default=0) - extra_info = jsonfield.JSONField(_('extra information'), default={}) + extra_info = models.TextField(_('extra information'), default='{}') gazeta_link = models.CharField(blank=True, max_length=240) wiki_link = models.CharField(blank=True, max_length=240) print_on_demand = models.BooleanField(_('print on demand'), default=False) @@ -128,6 +128,9 @@ class Book(models.Model): def __str__(self): return self.title + def get_extra_info_json(self): + return json.loads(self.extra_info or '{}') + def get_initial(self): try: return re.search(r'\w', self.title, re.U).group(0) @@ -169,7 +172,7 @@ class Book(models.Model): return self.tag_unicode('genre') def translator(self): - translators = self.extra_info.get('translators') + translators = self.get_extra_info_json().get('translators') if not translators: return None if len(translators) > 3: @@ -180,7 +183,7 @@ class Book(models.Model): return ', '.join(u'\xa0'.join(reversed(translator.split(', ', 1))) for translator in translators) + others def cover_source(self): - return self.extra_info.get('cover_source', self.parent.cover_source() if self.parent else '') + return self.get_extra_info_json().get('cover_source', self.parent.cover_source() if self.parent else '') def save(self, force_insert=False, force_update=False, **kwargs): from sortify import sortify @@ -195,7 +198,7 @@ class Book(models.Model): self.sort_key_author = author self.cached_author = self.tag_unicode('author') - self.has_audience = 'audience' in self.extra_info + self.has_audience = 'audience' in self.get_extra_info_json() if self.preview and not self.preview_key: self.preview_key = get_random_hash(self.slug)[:32] @@ -340,7 +343,7 @@ class Book(models.Model): projects = set() for mp3 in self.media.filter(type='mp3').iterator(): # ogg files are always from the same project - meta = mp3.extra_info + meta = mp3.get_extra_info_json() project = meta.get('project') if not project: # temporary fallback @@ -377,7 +380,7 @@ class Book(models.Model): def zip_format(format_): def pretty_file_name(book): return "%s/%s.%s" % ( - book.extra_info['author'], + book.get_extra_info_json()['author'], book.slug, format_) @@ -490,7 +493,7 @@ class Book(models.Model): book.common_slug = book_info.variant_of.slug else: book.common_slug = book.slug - book.extra_info = book_info.to_dict() + book.extra_info = json.dumps(book_info.to_dict()) book.load_abstract() book.save() @@ -603,7 +606,7 @@ class Book(models.Model): need = False info = {} for field in ('cover_url', 'cover_by', 'cover_source'): - val = self.extra_info.get(field) + val = self.get_extra_info_json().get(field) if val: info[field] = val else: @@ -657,7 +660,7 @@ class Book(models.Model): return ', '.join(names) def publisher(self): - publisher = self.extra_info['publisher'] + publisher = self.get_extra_info_json()['publisher'] if isinstance(publisher, str): return publisher elif isinstance(publisher, list): @@ -724,12 +727,12 @@ class Book(models.Model): } def audiences_pl(self): - audiences = self.extra_info.get('audiences', []) + audiences = self.get_extra_info_json().get('audiences', []) audiences = sorted(set([self._audiences_pl.get(a, (99, a)) for a in audiences])) return [a[1] for a in audiences] def stage_note(self): - stage = self.extra_info.get('stage') + stage = self.get_extra_info_json().get('stage') if stage and stage < '0.4': return (_('This work needs modernisation'), reverse('infopage', args=['wymagajace-uwspolczesnienia'])) @@ -786,7 +789,7 @@ class Book(models.Model): return self.SORT_KEY_SEP.join((self.sort_key_author, self.sort_key, str(self.id))) def cover_color(self): - return WLCover.epoch_colors.get(self.extra_info.get('epoch'), '#000000') + return WLCover.epoch_colors.get(self.get_extra_info_json().get('epoch'), '#000000') @cached_render('catalogue/book_mini_box.html') def mini_box(self): diff --git a/src/catalogue/models/bookmedia.py b/src/catalogue/models/bookmedia.py index 9f71364a8..d1f2bf04d 100644 --- a/src/catalogue/models/bookmedia.py +++ b/src/catalogue/models/bookmedia.py @@ -6,7 +6,6 @@ import json from collections import namedtuple from django.db import models from django.utils.translation import ugettext_lazy as _ -import jsonfield from slugify import slugify from mutagen import MutagenError @@ -33,7 +32,7 @@ class BookMedia(models.Model): index = models.IntegerField(_('index'), default=0) file = models.FileField(_('file'), max_length=600, upload_to=_file_upload_to, storage=OverwriteStorage()) uploaded_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False, db_index=True) - extra_info = jsonfield.JSONField(_('extra information'), default={}, editable=False) + extra_info = models.TextField(_('extra information'), default='{}', editable=False) book = models.ForeignKey('Book', models.CASCADE, related_name='media') source_sha1 = models.CharField(null=True, blank=True, max_length=40, editable=False) @@ -46,6 +45,9 @@ class BookMedia(models.Model): verbose_name_plural = _('book media') app_label = 'catalogue' + def get_extra_info_json(self): + return json.loads(self.extra_info or '{}') + def save(self, parts_count=None, *args, **kwargs): from catalogue.utils import ExistingFile, remove_zip @@ -75,12 +77,9 @@ class BookMedia(models.Model): remove_zip("%s_%s" % (old.book.slug, old.type)) remove_zip("%s_%s" % (self.book.slug, self.type)) - extra_info = self.extra_info - if isinstance(extra_info, str): - # Walkaround for weird jsonfield 'no-decode' optimization. - extra_info = json.loads(extra_info) + extra_info = self.get_extra_info_json() extra_info.update(self.read_meta()) - self.extra_info = extra_info + self.extra_info = json.dumps(extra_info) self.source_sha1 = self.read_source_sha1(self.file.path, self.type) return super(BookMedia, self).save(*args, **kwargs) @@ -148,11 +147,11 @@ class BookMedia(models.Model): @property def director(self): - return self.extra_info.get('director_name', None) + return self.get_extra_info_json().get('director_name', None) @property def artist(self): - return self.extra_info.get('artist_name', None) + return self.get_extra_info_json().get('artist_name', None) def file_url(self): return self.file.url diff --git a/src/catalogue/models/source.py b/src/catalogue/models/source.py index c678cad51..08cac0cce 100644 --- a/src/catalogue/models/source.py +++ b/src/catalogue/models/source.py @@ -37,7 +37,7 @@ class Source(models.Model): # and invalidate their cached includes. if old_name != self.name or old_netloc != self.netloc: for book in Book.objects.all(): - source = book.extra_info.get('source_url', '') + source = book.get_extra_info_json().get('source_url', '') if self.netloc in source or (old_netloc != self.netloc and old_netloc in source): book.clear_cache() return ret diff --git a/src/catalogue/templates/catalogue/book_info.html b/src/catalogue/templates/catalogue/book_info.html index 014a9836a..85d1fbc06 100755 --- a/src/catalogue/templates/catalogue/book_info.html +++ b/src/catalogue/templates/catalogue/book_info.html @@ -1,10 +1,11 @@ {% load i18n %} {% load catalogue_tags %} +{% with extra_info=book.get_extra_info_json %}

- {% if book.extra_info.license %} + {% if extra_info.license %} {% trans "This work is licensed under:" %} - {{ book.extra_info.license_description }} + {{ extra_info.license_description }} {% else %} {% blocktrans %}This work isn't covered by copyright and is part of the public domain, which means it can be freely used, published and @@ -16,48 +17,50 @@ {% endif %}

-{% if book.extra_info.source_name %} -

{% trans "Resource prepared based on:" %} {{ book.extra_info.source_name }}

+{% if extra_info.source_name %} +

{% trans "Resource prepared based on:" %} {{ extra_info.source_name }}

{% endif %} -{% if book.extra_info.description %} -

{{ book.extra_info.description }}

+{% if extra_info.description %} +

{{ extra_info.description }}

{% endif %} -{% if book.extra_info.editor or book.extra_info.technical_editor %} +{% if extra_info.editor or extra_info.technical_editor %}

{% if is_picture %} {% trans "Edited by:" %} {% else %} {% trans "Edited and annotated by:" %} {% endif %} - {% all_editors book.extra_info %}. + {% all_editors extra_info %}.

{% endif %} -{% if book.extra_info.publisher %} +{% if extra_info.publisher %}

{% trans "Publisher:" %} {{ book.publisher }}

{% endif %} -{% if book.extra_info.funders %} +{% if extra_info.funders %}

{% trans "Publication funded by:" %} - {% for funder in book.extra_info.funders %}{{ funder }}{% if not forloop.last %}, {% else %}.{% endif %}{% endfor %} + {% for funder in extra_info.funders %}{{ funder }}{% if not forloop.last %}, {% else %}.{% endif %}{% endfor %}

{% endif %} -{% if book.extra_info.cover_by %} +{% if extra_info.cover_by %}

{% trans "Cover image by:" %} - {{ book.extra_info.cover_by }}. + {{ extra_info.cover_by }}.

{% endif %} -{% if book.extra_info.isbn_html %} +{% if extra_info.isbn_html %}

- {{ book.extra_info.isbn_html }} + {{ extra_info.isbn_html }}

{% endif %} + +{% endwith %} diff --git a/src/catalogue/templates/catalogue/book_short.html b/src/catalogue/templates/catalogue/book_short.html index ccb100446..59debf42c 100644 --- a/src/catalogue/templates/catalogue/book_short.html +++ b/src/catalogue/templates/catalogue/book_short.html @@ -73,12 +73,14 @@ {% endfor %} - {% if book.extra_info.location %} - - {% trans "Region" %}:  - {{ book.extra_info.location }} - - {% endif %} + {% with extra_info=book.get_extra_info_json %} + {% if extra_info.location %} + + {% trans "Region" %}:  + {{ extra_info.location }} + + {% endif %} + {% endwith %} {% if book.is_foreign %} diff --git a/src/catalogue/templates/catalogue/book_wide.html b/src/catalogue/templates/catalogue/book_wide.html index ad0384c48..7721c2376 100644 --- a/src/catalogue/templates/catalogue/book_wide.html +++ b/src/catalogue/templates/catalogue/book_wide.html @@ -8,9 +8,11 @@ {% block cover-area-extra %} - {% if book.extra_info.license %} - {% license_icon book.extra_info.license %} - {% endif %} + {% with license=book.get_extra_info_json.license %} + {% if license %} + {% license_icon license %} + {% endif %} + {% endwith %} {% endblock %} diff --git a/src/catalogue/templates/catalogue/snippets/jplayer.html b/src/catalogue/templates/catalogue/snippets/jplayer.html index 46eef4066..8847f99a0 100644 --- a/src/catalogue/templates/catalogue/snippets/jplayer.html +++ b/src/catalogue/templates/catalogue/snippets/jplayer.html @@ -32,13 +32,15 @@
  • {{ i.mp3.name }}
    - {% trans "Artist:" %} {{ i.mp3.extra_info.artist_name }}, - {% trans "director:" %} {{ i.mp3.extra_info.director_name }} + {% with extra_info=i.mp3.get_extra_info_json %} + {% trans "Artist:" %} {{ extra_info.artist_name }}, + {% trans "director:" %} {{ extra_info.director_name }}

    - {% with fb=i.mp3.extra_info.funded_by %} + {% with fb=extra_info.funded_by %} {% if fb %}Dofinansowano ze środków: {{ fb }}.{% endif %} {% endwith %}

    + {% endwith %}
  • diff --git a/src/catalogue/views.py b/src/catalogue/views.py index ccd51ff68..b4ac30f86 100644 --- a/src/catalogue/views.py +++ b/src/catalogue/views.py @@ -457,4 +457,4 @@ def ridero_cover(request, slug): def get_isbn(request, book_format, slug): book = Book.objects.get(slug=slug) - return HttpResponse(book.extra_info.get('isbn_%s' % book_format)) + return HttpResponse(book.get_extra_info_json().get('isbn_%s' % book_format)) diff --git a/src/contact/admin.py b/src/contact/admin.py index a05943381..32d12ec27 100644 --- a/src/contact/admin.py +++ b/src/contact/admin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import csv import json @@ -36,7 +35,7 @@ class ContactAdmin(admin.ModelAdmin): except BaseException: return '' else: - return Contact.pretty_print(obj.body.get(field_name, ''), for_html=True) + return Contact.pretty_print(obj.get_body_json().get(field_name, ''), for_html=True) def __getattr__(self, name): if name.startswith('admin_list_'): @@ -48,13 +47,14 @@ class ContactAdmin(admin.ModelAdmin): if object_id: try: instance = Contact.objects.get(pk=object_id) - assert isinstance(instance.body, dict) + body = instance.get_body_json() + assert isinstance(body, dict) except (Contact.DoesNotExist, AssertionError): pass else: # Create readonly fields from the body JSON. attachments = list(instance.attachment_set.all()) - body_keys = instance.body.keys() + [a.tag for a in attachments] + body_keys = body.keys() + [a.tag for a in attachments] # Find the original form. try: @@ -82,7 +82,7 @@ class ContactAdmin(admin.ModelAdmin): f.short_description = orig_fields[key].label if key in orig_fields else _(key) setattr(self, "body__%s" % key, f) - for k, v in instance.body.items(): + for k, v in body.items(): attach_getter(k, Contact.pretty_print(v, for_html=True)) download_link = "%(url)s" @@ -133,7 +133,7 @@ def extract_view(request, form_tag, extract_type_slug): if extract_type_slug == 'contacts': keys = ['contact'] elif extract_type_slug == 'all': - keys = contact.body.keys() + ['contact'] + keys = contact.get_body_json().keys() + ['contact'] keys = [key for key in orig_keys if key in keys] + [key for key in keys if key not in orig_keys] else: keys = form.get_extract_fields(contact, extract_type_slug) @@ -149,7 +149,7 @@ def extract_view(request, form_tag, extract_type_slug): if extract_type_slug == 'contacts': records = [dict(contact=contact.contact)] elif extract_type_slug == 'all': - records = [dict(contact=contact.contact, **contact.body)] + records = [dict(contact=contact.contact, **contact.get_body_json())] else: records = form.get_extract_records(keys, contact, extract_type_slug) diff --git a/src/contact/forms.py b/src/contact/forms.py index ff1687adb..ee44e4b19 100644 --- a/src/contact/forms.py +++ b/src/contact/forms.py @@ -1,3 +1,4 @@ +import json from django.contrib.sites.models import Site from django.core.exceptions import ValidationError from django.core.files.uploadedfile import UploadedFile @@ -56,7 +57,7 @@ class ContactForm(forms.Form): body.setdefault(f.form_tag, []).append(sub_body) contact = Contact.objects.create( - body=body, + body=json.dumps(body), ip=request.META['REMOTE_ADDR'], contact=self.cleaned_data['contact'], form_tag=self.form_tag) diff --git a/src/contact/migrations/0001_initial.py b/src/contact/migrations/0001_initial.py index 216c4c508..682a097b6 100644 --- a/src/contact/migrations/0001_initial.py +++ b/src/contact/migrations/0001_initial.py @@ -1,6 +1,5 @@ from django.db import migrations, models import django.db.models.deletion -import jsonfield.fields class Migration(migrations.Migration): @@ -25,7 +24,7 @@ class Migration(migrations.Migration): ('ip', models.GenericIPAddressField(verbose_name='IP address')), ('contact', models.EmailField(max_length=128, verbose_name='contact')), ('form_tag', models.CharField(max_length=32, verbose_name='form', db_index=True)), - ('body', jsonfield.fields.JSONField(verbose_name='body')), + ('body', models.TextField(verbose_name='body')), ], options={ 'ordering': ('-created_at',), diff --git a/src/contact/models.py b/src/contact/models.py index aae3f2dcd..b173b4d21 100644 --- a/src/contact/models.py +++ b/src/contact/models.py @@ -1,10 +1,10 @@ +import json import yaml from hashlib import sha1 from django.db import models from django.urls import reverse from django.utils.encoding import smart_text from django.utils.translation import ugettext_lazy as _ -from jsonfield import JSONField from . import app_settings @@ -13,7 +13,7 @@ class Contact(models.Model): ip = models.GenericIPAddressField(_('IP address')) contact = models.EmailField(_('contact'), max_length=128) form_tag = models.CharField(_('form'), max_length=32, db_index=True) - body = JSONField(_('body')) + body = models.TextField(_('body')) @staticmethod def pretty_print(value, for_html=False): @@ -32,7 +32,7 @@ class Contact(models.Model): return str(self.created_at) def digest(self): - serialized_body = ';'.join(sorted('%s:%s' % item for item in self.body.items())) + serialized_body = ';'.join(sorted('%s:%s' % item for item in self.get_body_json().items())) data = '%s%s%s%s%s' % (self.id, self.contact, serialized_body, self.ip, self.form_tag) return sha1(data).hexdigest() @@ -45,7 +45,11 @@ class Contact(models.Model): return list(orig_fields.keys()) def items(self): - return [(key, self.body[key]) for key in self.keys() if key in self.body] + body = self.get_body_json() + return [(key, body[key]) for key in self.keys() if key in body] + + def get_body_json(self): + return json.loads(self.body or '{}') class Attachment(models.Model): diff --git a/src/dictionary/templates/dictionary/note_list.html b/src/dictionary/templates/dictionary/note_list.html index 3083e0479..3a19b4ec8 100755 --- a/src/dictionary/templates/dictionary/note_list.html +++ b/src/dictionary/templates/dictionary/note_list.html @@ -100,7 +100,7 @@ {% for note_source in obj.notesource_set.all %} {% endfor %} diff --git a/src/isbn/forms.py b/src/isbn/forms.py index 47a72baf2..5f2940c2f 100644 --- a/src/isbn/forms.py +++ b/src/isbn/forms.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- from datetime import date +import json from urllib.request import urlopen from django import forms @@ -48,7 +48,7 @@ class WLConfirmForm(WLISBNForm): for file_format in data['formats']: data['product_form'] = PRODUCT_FORMS[file_format] data['product_form_detail'] = PRODUCT_FORM_DETAILS[file_format] - data['contributors'] = self.contributors(data) + data['contributors'] = json.dumps(self.contributors(data)) ONIXRecord.new_record(purpose=ISBNPool.PURPOSE_WL, data=data) return data @@ -93,7 +93,7 @@ class FNPISBNForm(forms.Form): 'title': self.cleaned_data['title'], 'language': self.cleaned_data['language'], 'publishing_date': self.cleaned_data['publishing_date'], - 'contributors': [self.prepare_author(a) for a in self.cleaned_data['authors'].split(',')], + 'contributors': json.dumps([self.prepare_author(a) for a in self.cleaned_data['authors'].split(',')]), 'edition_type': 'NED', 'imprint': 'Fundacja Nowoczesna Polska', 'dc_slug': self.slug(), diff --git a/src/isbn/management/commands/export_onix.py b/src/isbn/management/commands/export_onix.py index a78e882fa..860bc7985 100644 --- a/src/isbn/management/commands/export_onix.py +++ b/src/isbn/management/commands/export_onix.py @@ -1,3 +1,4 @@ +import json from django.core.management.base import BaseCommand from django.utils import timezone @@ -123,7 +124,7 @@ class Command(BaseCommand): else: part_number = '' contributors = '' - for no, contributor in enumerate(record.contributors, start=1): + for no, contributor in enumerate(json.loads(record.contributors), start=1): contributors += self.render_contributor(no, contributor) return PRODUCT % { 'datestamp': record.datestamp.strftime('%Y%m%d'), diff --git a/src/isbn/migrations/0001_initial.py b/src/isbn/migrations/0001_initial.py index b3c9aec50..78a45b9f0 100644 --- a/src/isbn/migrations/0001_initial.py +++ b/src/isbn/migrations/0001_initial.py @@ -1,6 +1,5 @@ from django.db import migrations, models import django.db.models.deletion -import jsonfield.fields class Migration(migrations.Migration): @@ -30,7 +29,7 @@ class Migration(migrations.Migration): ('product_form_detail', models.CharField(max_length=8, blank=True)), ('title', models.CharField(max_length=256)), ('part_number', models.CharField(max_length=64, blank=True)), - ('contributors', jsonfield.fields.JSONField()), + ('contributors', models.TextField()), ('edition_type', models.CharField(max_length=4)), ('edition_number', models.IntegerField(default=1)), ('language', models.CharField(max_length=4)), diff --git a/src/isbn/models.py b/src/isbn/models.py index d65ca606c..b5e5de3a2 100644 --- a/src/isbn/models.py +++ b/src/isbn/models.py @@ -3,7 +3,6 @@ # from django.db import models from django.db.models import F -from jsonfield import JSONField class ISBNPool(models.Model): @@ -59,7 +58,7 @@ class ONIXRecord(models.Model): product_form_detail = models.CharField(max_length=8, blank=True) title = models.CharField(max_length=256) part_number = models.CharField(max_length=64, blank=True) - contributors = JSONField() # roles, names, optional: ISNI, date of birth/death + contributors = models.TextField() # roles, names, optional: ISNI, date of birth/death edition_type = models.CharField(max_length=4) edition_number = models.IntegerField(default=1) language = models.CharField(max_length=4) diff --git a/src/lesmianator/migrations/0001_initial.py b/src/lesmianator/migrations/0001_initial.py index f8741e4cb..3199bf04d 100644 --- a/src/lesmianator/migrations/0001_initial.py +++ b/src/lesmianator/migrations/0001_initial.py @@ -1,6 +1,5 @@ from django.db import models, migrations import django.db.models.deletion -import jsonfield.fields from django.conf import settings @@ -30,7 +29,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('slug', models.SlugField(max_length=120, verbose_name='Slug')), ('text', models.TextField(verbose_name='text')), - ('created_from', jsonfield.fields.JSONField(null=True, verbose_name='Additional information', blank=True)), + ('created_from', models.TextField(null=True, verbose_name='Additional information', blank=True)), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='creation date')), ('seen_at', models.DateTimeField(auto_now_add=True, verbose_name='last view date')), ('view_count', models.IntegerField(default=1, verbose_name='view count')), diff --git a/src/lesmianator/migrations/0002_auto_20151221_1225.py b/src/lesmianator/migrations/0002_auto_20151221_1225.py index 29a33a85c..94d653721 100644 --- a/src/lesmianator/migrations/0002_auto_20151221_1225.py +++ b/src/lesmianator/migrations/0002_auto_20151221_1225.py @@ -1,8 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models -import jsonfield.fields class Migration(migrations.Migration): @@ -15,7 +11,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='poem', name='created_from', - field=jsonfield.fields.JSONField(null=True, verbose_name='extra information', blank=True), + field=models.TextField(null=True, verbose_name='extra information', blank=True), ), migrations.AlterField( model_name='poem', diff --git a/src/lesmianator/models.py b/src/lesmianator/models.py index f12f1d778..00440a1fa 100644 --- a/src/lesmianator/models.py +++ b/src/lesmianator/models.py @@ -17,7 +17,6 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.conf import settings from django.urls import reverse -from jsonfield import JSONField from catalogue.models import Book, Tag @@ -25,7 +24,7 @@ class Poem(models.Model): slug = models.SlugField(_('slug'), max_length=120, db_index=True) text = models.TextField(_('text')) created_by = models.ForeignKey(User, models.SET_NULL, null=True) - created_from = JSONField(_('extra information'), null=True, blank=True) + created_from = models.TextField(_('extra information'), null=True, blank=True) created_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False) seen_at = models.DateTimeField(_('last view date'), auto_now_add=True, editable=False) view_count = models.IntegerField(_('view count'), default=1) diff --git a/src/lesmianator/views.py b/src/lesmianator/views.py index f814bbc99..3e8cfa5ff 100644 --- a/src/lesmianator/views.py +++ b/src/lesmianator/views.py @@ -1,7 +1,7 @@ -# -*- coding: utf-8 -*- # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # +import json from django.shortcuts import render, get_object_or_404 from django.views.decorators import cache @@ -38,7 +38,7 @@ def poem_from_book(request, slug): user = request.user if request.user.is_authenticated() else None text = Poem.write(Continuations.get(book)) p = Poem(slug=get_random_hash(text), text=text, created_by=user) - p.created_from = [book.id] + p.created_from = json.dumps([book.id]) p.save() return render( @@ -54,7 +54,7 @@ def poem_from_set(request, shelf): text = Poem.write(Continuations.get(tag)) p = Poem(slug=get_random_hash(text), text=text, created_by=user) books = Book.tagged.with_any((tag,)) - p.created_from = [b.id for b in books] + p.created_from = json.dumps([b.id for b in books]) p.save() book = books[0] if len(books) == 1 else None @@ -68,8 +68,9 @@ def poem_from_set(request, shelf): def get_poem(request, poem): p = get_object_or_404(Poem, slug=poem) p.visit() - if p.created_from: - books = Book.objects.filter(id__in=p.created_from) + created_from = json.loads(p.created_from or '[]') + if created_from: + books = Book.objects.filter(id__in=created_from) book = books[0] if len(books) == 1 else None else: books = book = None diff --git a/src/picture/migrations/0001_initial.py b/src/picture/migrations/0001_initial.py index 11321d40b..22611bb7b 100644 --- a/src/picture/migrations/0001_initial.py +++ b/src/picture/migrations/0001_initial.py @@ -3,7 +3,6 @@ from django.conf import settings from django.db import models, migrations import django.db.models.deletion import sorl.thumbnail.fields -import jsonfield.fields import django.core.files.storage @@ -26,11 +25,11 @@ class Migration(migrations.Migration): ('xml_file', models.FileField(upload_to='xml', storage=django.core.files.storage.FileSystemStorage(base_url='/media/pictures/', location=join(settings.MEDIA_ROOT, 'pictures')), verbose_name='xml_file')), ('image_file', sorl.thumbnail.fields.ImageField(upload_to='images', storage=django.core.files.storage.FileSystemStorage(base_url='/media/pictures/', location=join(settings.MEDIA_ROOT, 'pictures')), verbose_name='image_file')), ('html_file', models.FileField(upload_to='html', storage=django.core.files.storage.FileSystemStorage(base_url='/media/pictures/', location=join(settings.MEDIA_ROOT, 'pictures')), verbose_name='html_file')), - ('areas_json', jsonfield.fields.JSONField(default={}, verbose_name='picture areas JSON', editable=False)), - ('extra_info', jsonfield.fields.JSONField(default={}, verbose_name='Additional information')), + ('areas_json', models.TextField(default='{}', verbose_name='picture areas JSON', editable=False)), + ('extra_info', models.TextField(default={}, verbose_name='Additional information')), ('culturepl_link', models.CharField(max_length=240, blank=True)), ('wiki_link', models.CharField(max_length=240, blank=True)), - ('_related_info', jsonfield.fields.JSONField(null=True, editable=False, blank=True)), + ('_related_info', models.TextField(null=True, editable=False, blank=True)), ('width', models.IntegerField(null=True)), ('height', models.IntegerField(null=True)), ], @@ -45,7 +44,7 @@ class Migration(migrations.Migration): name='PictureArea', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('area', jsonfield.fields.JSONField(default={}, verbose_name='area', editable=False)), + ('area', models.TextField(default='{}', verbose_name='area', editable=False)), ('kind', models.CharField(db_index=True, max_length=10, verbose_name='form', choices=[('thing', 'thing'), ('theme', 'motif')])), ('picture', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='areas', to='picture.Picture')), ], diff --git a/src/picture/migrations/0005_auto_20141022_1001.py b/src/picture/migrations/0005_auto_20141022_1001.py index 7f8d346ec..9ece9d7df 100644 --- a/src/picture/migrations/0005_auto_20141022_1001.py +++ b/src/picture/migrations/0005_auto_20141022_1001.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - +import json from django.core.files.base import ContentFile from django.db import models, migrations from django.template.loader import render_to_string @@ -12,14 +10,14 @@ def rebuild_extra_info(apps, schema_editor): from librarian import dcparser for pic in Picture.objects.all(): info = dcparser.parse(pic.xml_file.path, PictureInfo) - pic.extra_info = info.to_dict() - areas_json = pic.areas_json - for field in areas_json[u'things'].values(): - field[u'object'] = field[u'object'].capitalize() - pic.areas_json = areas_json + pic.extra_info = json.dumps(info.to_dict()) + areas_json = json.loads(pic.areas_json) + for field in areas_json['things'].values(): + field['object'] = field['object'].capitalize() + pic.areas_json = json.dumps(areas_json) html_text = render_to_string('picture/picture_info.html', { - 'things': pic.areas_json['things'], - 'themes': pic.areas_json['themes'], + 'things': areas_json['things'], + 'themes': areas_json['themes'], }) pic.html_file.save("%s.html" % pic.slug, ContentFile(html_text)) pic.save() diff --git a/src/picture/migrations/0006_auto_20151221_1225.py b/src/picture/migrations/0006_auto_20151221_1225.py index 9f1a82c5b..50f97b50e 100644 --- a/src/picture/migrations/0006_auto_20151221_1225.py +++ b/src/picture/migrations/0006_auto_20151221_1225.py @@ -1,8 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models -import jsonfield.fields class Migration(migrations.Migration): @@ -15,7 +11,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='picture', name='extra_info', - field=jsonfield.fields.JSONField(default={}, verbose_name='extra information'), + field=models.TextField(default='{}', verbose_name='extra information'), ), migrations.AlterField( model_name='picture', diff --git a/src/picture/models.py b/src/picture/models.py index 75d84e2eb..1ad09e2d8 100644 --- a/src/picture/models.py +++ b/src/picture/models.py @@ -15,8 +15,8 @@ from catalogue.utils import split_tags from picture import tasks from wolnelektury.utils import cached_render, clear_cached_renders from io import BytesIO -import jsonfield import itertools +import json import logging import re @@ -34,7 +34,7 @@ picture_storage = FileSystemStorage(location=path.join( class PictureArea(models.Model): picture = models.ForeignKey('picture.Picture', models.CASCADE, related_name='areas') - area = jsonfield.JSONField(_('area'), default={}, editable=False) + area = models.TextField(_('area'), default='{}', editable=False) kind = models.CharField( _('kind'), max_length=10, blank=False, null=False, db_index=True, choices=(('thing', _('thing')), ('theme', _('theme')))) @@ -51,9 +51,12 @@ class PictureArea(models.Model): pa = PictureArea() pa.picture = picture pa.kind = kind - pa.area = coords + pa.area = json.dumps(coords) return pa + def get_area_json(self): + return json.loads(self.area) + @cached_render('picture/picturearea_short.html') def midi_box(self): themes = self.tags.filter(category='theme') @@ -77,14 +80,14 @@ class Picture(models.Model): slug = models.SlugField(_('slug'), max_length=120, db_index=True, unique=True) sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False) sort_key_author = models.CharField( - _('sort key by author'), max_length=120, db_index=True, editable=False, default=u'') + _('sort key by author'), max_length=120, db_index=True, editable=False, default='') created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True) changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True) xml_file = models.FileField(_('xml file'), upload_to="xml", storage=picture_storage) image_file = ImageField(_('image file'), upload_to="images", storage=picture_storage) html_file = models.FileField(_('html file'), upload_to="html", storage=picture_storage) - areas_json = jsonfield.JSONField(_('picture areas JSON'), default={}, editable=False) - extra_info = jsonfield.JSONField(_('extra information'), default={}) + areas_json = models.TextField(_('picture areas JSON'), default='{}', editable=False) + extra_info = models.TextField(_('extra information'), default='{}') culturepl_link = models.CharField(blank=True, max_length=240) wiki_link = models.CharField(blank=True, max_length=240) @@ -196,7 +199,7 @@ class Picture(models.Model): picture.areas.all().delete() picture.title = str(picture_xml.picture_info.title) - picture.extra_info = picture_xml.picture_info.to_dict() + picture.extra_info = json.dumps(picture_xml.picture_info.to_dict()) picture_tags = set(catalogue.models.Tag.tags_from_info(picture_xml.picture_info)) for tag in picture_tags: @@ -268,7 +271,7 @@ class Picture(models.Model): area.tags = _tags.union(picture_tags) picture.tags = picture_tags - picture.areas_json = area_data + picture.areas_json = json.dumps(area_data) if image_file is not None: img = image_file diff --git a/src/picture/tasks.py b/src/picture/tasks.py index e80b0fc77..e815f190c 100644 --- a/src/picture/tasks.py +++ b/src/picture/tasks.py @@ -1,7 +1,7 @@ -# -*- coding: utf-8 -*- # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # +import json from traceback import print_exc from celery.task import task @@ -13,10 +13,11 @@ from django.template.loader import render_to_string def generate_picture_html(picture_id): import picture.models pic = picture.models.Picture.objects.get(pk=picture_id) + areas_json = json.loads(pic.areas_json) html_text = render_to_string('picture/picture_info.html', { - 'things': pic.areas_json['things'], - 'themes': pic.areas_json['themes'], + 'things': areas_json['things'], + 'themes': areas_json['themes'], }) pic.html_file.save("%s.html" % pic.slug, ContentFile(html_text)) diff --git a/src/picture/templates/picture/picture_wide.html b/src/picture/templates/picture/picture_wide.html index 3ca7afe89..884b46caa 100644 --- a/src/picture/templates/picture/picture_wide.html +++ b/src/picture/templates/picture/picture_wide.html @@ -15,10 +15,11 @@ {% block extra_categories %} - {% if picture.extra_info.styles %} + {% with extra_info=picture.get_extra_info_json %} + {% if extra_info.styles %} {% trans "Style" %}:  - {% for tag in picture.extra_info.styles %} + {% for tag in extra_info.styles %} {{ tag }} {% if not forloop.last %}, {% endif %} {% endfor %} @@ -26,27 +27,28 @@ {% endif %} - {% if picture.extra_info.medium %} + {% if extra_info.medium %} {% trans "Medium" %}:  - {{ picture.extra_info.medium }} + {{ extra_info.medium }} {% endif %} - {% if picture.extra_info.original_dimensions %} + {% if extra_info.original_dimensions %} {% trans "Dimensions" %}:  - {{ picture.extra_info.original_dimensions }} + {{ extra_info.original_dimensions }} {% endif %} {% trans "Date" %}:  - {{ picture.extra_info.created_at }} + {{ extra_info.created_at }} + {% endwith %} {% endblock %} @@ -82,16 +84,17 @@ {% block right-column %} + {% with extra_info=picture.get_extra_info_json %}

    {% trans "See" %}

    + {% endwith %} {% endblock %} diff --git a/src/picture/templatetags/picture_tags.py b/src/picture/templatetags/picture_tags.py index 70d58e0c0..43f2775d7 100644 --- a/src/picture/templatetags/picture_tags.py +++ b/src/picture/templatetags/picture_tags.py @@ -46,7 +46,7 @@ def area_thumbnail_url(area, geometry): # what to do about this? _engine = sorl.thumbnail.default.engine sorl.thumbnail.default.engine = cropper - coords = to_square(area.area) + coords = to_square(area.get_area_json()) try: th = sorl.thumbnail.default.backend.get_thumbnail( diff --git a/src/picture/views.py b/src/picture/views.py index 6345f2008..43601a180 100644 --- a/src/picture/views.py +++ b/src/picture/views.py @@ -36,7 +36,7 @@ def picture_detail(request, slug): def picture_viewer(request, slug): picture = get_object_or_404(Picture, slug=slug) sponsors = [] - for sponsor in picture.extra_info.get('sponsors', []): + for sponsor in picture.get_extra_info_json().get('sponsors', []): have_sponsors = Sponsor.objects.filter(name=sponsor) if have_sponsors.exists(): sponsors.append(have_sponsors[0]) @@ -60,7 +60,7 @@ def picture_page(request, key=None): 'epoch': picture.tag_unicode('epoch'), 'kind': picture.tag_unicode('kind'), 'genre': picture.tag_unicode('genre'), - 'style': picture.extra_info['style'], + 'style': picture.get_extra_info_json()['style'], 'image_url': picture.image_file.url, 'width': picture.width, 'height': picture.height, diff --git a/src/reporting/views.py b/src/reporting/views.py index cc1bf7ee5..9eecf0d55 100644 --- a/src/reporting/views.py +++ b/src/reporting/views.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # @@ -25,9 +24,11 @@ def stats_page(request): else: mt['deprecated'] = '-' - licenses = set( - (b.extra_info.get('license'), b.extra_info.get('license_description')) - for b in Book.objects.all().iterator() if b.extra_info.get('license')) + licenses = set() + for b in Book.objects.all().iterator(): + extra_info = b.get_extra_info_json() + if extra_info.get('license'): + licenses.add((extra_info.get('license'), extra_info.get('license_description'))) return render(request, 'reporting/main.html', { 'media_types': media_types, diff --git a/src/sponsors/admin.py b/src/sponsors/admin.py index 274fe901e..df11973e6 100644 --- a/src/sponsors/admin.py +++ b/src/sponsors/admin.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from django.contrib import admin -from jsonfield import JSONField +from django.db.models import TextField from sponsors import models from sponsors import widgets @@ -16,7 +15,7 @@ class SponsorAdmin(admin.ModelAdmin): class SponsorPageAdmin(admin.ModelAdmin): formfield_overrides = { - JSONField: {'widget': widgets.SponsorPageWidget}, + TextField: {'widget': widgets.SponsorPageWidget}, } list_display = ('name',) search_fields = ('name',) diff --git a/src/sponsors/migrations/0001_initial.py b/src/sponsors/migrations/0001_initial.py index becb6fa16..5f4b523f1 100644 --- a/src/sponsors/migrations/0001_initial.py +++ b/src/sponsors/migrations/0001_initial.py @@ -1,8 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import models, migrations -import jsonfield.fields class Migration(migrations.Migration): @@ -29,7 +25,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=120, verbose_name='name')), - ('sponsors', jsonfield.fields.JSONField(default={}, verbose_name='sponsors')), + ('sponsors', models.TextField(default='{}', verbose_name='sponsors')), ('_html', models.TextField(editable=False, blank=True)), ('sprite', models.ImageField(upload_to='sponsorzy/sprite', blank=True)), ], diff --git a/src/sponsors/models.py b/src/sponsors/models.py index c193f427e..6e4ffe1f3 100644 --- a/src/sponsors/models.py +++ b/src/sponsors/models.py @@ -10,7 +10,6 @@ from django.utils.translation import ugettext_lazy as _ from django.template.loader import render_to_string from PIL import Image -from jsonfield import JSONField from django.core.files.base import ContentFile THUMB_WIDTH = 120 @@ -35,14 +34,17 @@ class Sponsor(models.Model): class SponsorPage(models.Model): name = models.CharField(_('name'), max_length=120) - sponsors = JSONField(_('sponsors'), default={}) + sponsors = models.TextField(_('sponsors'), default='{}') _html = models.TextField(blank=True, editable=False) sprite = models.ImageField(upload_to='sponsorzy/sprite', blank=True) + def get_sponsors_json(self): + return json.loads(self.sponsors or '[]') + def populated_sponsors(self): result = [] offset = 0 - for column in self.sponsors: + for column in self.get_sponsors_json(): result_group = {'name': column['name'], 'sponsors': []} sponsor_objects = Sponsor.objects.in_bulk(column['sponsors']) for sponsor_pk in column['sponsors']: @@ -56,7 +58,7 @@ class SponsorPage(models.Model): def render_sprite(self): sponsor_ids = [] - for column in self.sponsors: + for column in self.get_sponsors_json(): sponsor_ids.extend(column['sponsors']) sponsors = Sponsor.objects.in_bulk(sponsor_ids) sprite = Image.new('RGBA', (THUMB_WIDTH, len(sponsors) * THUMB_HEIGHT)) @@ -87,9 +89,6 @@ class SponsorPage(models.Model): html = property(fget=html) def save(self, *args, **kwargs): - if isinstance(self.sponsors, str): - # Walkaround for weird jsonfield 'no-decode' optimization. - self.sponsors = json.loads(self.sponsors) self.render_sprite() self._html = render_to_string('sponsors/page.html', { 'sponsors': self.populated_sponsors(),