diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index 2f7b7844..53f162a8 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -368,7 +368,7 @@ class Annotation(models.Model): if key in self._clip_keys: j[key] = getattr(self.clip, key) elif key not in self.annotation_keys: - value = self.item.get(key) or self.item.json.get(key) + value = self.item.get(key) or self.item.cache.get(key) if not value and hasattr(self.item.sort, key): value = getattr(self.item.sort, key) if value != None: diff --git a/pandora/archive/managers.py b/pandora/archive/managers.py index eba14343..a5d176a3 100644 --- a/pandora/archive/managers.py +++ b/pandora/archive/managers.py @@ -4,7 +4,6 @@ from django.db.models import Q, Manager from oxdjango.managers import get_operator from oxdjango.query import QuerySet -from oxdjango.fields import DictField keymap = { @@ -36,8 +35,7 @@ def parseCondition(condition, user): if isinstance(v, bool): key = k elif k == 'url': - key = 'info' + get_operator('=', 'istr') - v = DictField.dumps({'url': v})[1:-1] + key = 'info__url' + get_operator('=', 'istr') elif k == 'list': q = Q(id=0) l = v.split(":") diff --git a/pandora/archive/migrations/0004_jsonfield.py b/pandora/archive/migrations/0004_jsonfield.py new file mode 100644 index 00000000..5e1f433c --- /dev/null +++ b/pandora/archive/migrations/0004_jsonfield.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archive', '0003_auto_20161104_1726'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "archive_file" ALTER COLUMN "info" TYPE jsonb USING "info"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "archive_stream" ALTER COLUMN "info" TYPE jsonb USING "info"::text::jsonb' + ), + ] diff --git a/pandora/archive/models.py b/pandora/archive/models.py index a406d4a4..4c756508 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -13,6 +13,7 @@ from django.contrib.auth.models import User from django.db import models from django.db.models.signals import pre_delete from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField from oxdjango import fields import ox @@ -69,7 +70,7 @@ class File(models.Model): size = models.BigIntegerField(default=0) duration = models.FloatField(null=True) - info = fields.DictField(default={}) + info = JSONField(default=dict, editable=False) video_codec = models.CharField(max_length=255) pixel_format = models.CharField(max_length=255) @@ -687,7 +688,7 @@ class Stream(models.Model): source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True) available = models.BooleanField(default=False) oshash = models.CharField(max_length=16, null=True, db_index=True) - info = fields.DictField(default={}) + info = JSONField(default=dict, editable=False) duration = models.FloatField(default=0) aspect_ratio = models.FloatField(default=0) diff --git a/pandora/changelog/migrations/0002_jsonfield.py b/pandora/changelog/migrations/0002_jsonfield.py new file mode 100644 index 00000000..f2bd935f --- /dev/null +++ b/pandora/changelog/migrations/0002_jsonfield.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('changelog', '0001_initial'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "changelog_changelog" ALTER COLUMN "value" TYPE jsonb USING "value"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "changelog_log" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + ] diff --git a/pandora/changelog/models.py b/pandora/changelog/models.py index 1df9d728..31b955a2 100644 --- a/pandora/changelog/models.py +++ b/pandora/changelog/models.py @@ -6,8 +6,8 @@ from datetime import datetime from django.contrib.auth.models import User from django.db import models from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField -from oxdjango import fields import ox import websocket @@ -21,7 +21,7 @@ FIXME: remove this table more migrate to new ChangeLog class Changelog(models.Model): created = models.DateTimeField(auto_now_add=True) type = models.CharField(max_length=255, db_index=True) - value = fields.DictField(default={}) + value = JSONField(default=dict, editable=False) def __str__(self): return u'%s %s' % (self.type, self.created) @@ -52,7 +52,7 @@ def add_changelog(request, data, id=None): class Log(models.Model): action = models.CharField(max_length=255, db_index=True) - data = fields.DictField(default={}) + data = JSONField(default=dict, editable=False) created = models.DateTimeField(db_index=True) user = models.ForeignKey(User, null=True, related_name='changelog') changeid = models.TextField() diff --git a/pandora/clip/models.py b/pandora/clip/models.py index 121040fc..82e446d4 100644 --- a/pandora/clip/models.py +++ b/pandora/clip/models.py @@ -131,7 +131,7 @@ class MetaClip(object): if key == 'streams': value = [s.file.oshash for s in self.item.streams()] else: - value = self.item.get(key) or self.item.json.get(key) + value = self.item.get(key) or self.item.cache.get(key) if not value and hasattr(self.item.sort, key): value = getattr(self.item.sort, key) if value is not None: @@ -148,10 +148,10 @@ class MetaClip(object): qs = self.annotations.all() if qs.count(): data['annotation'] = qs[0].public_id - data['parts'] = self.item.json['parts'] - data['durations'] = self.item.json['durations'] + data['parts'] = self.item.cache['parts'] + data['durations'] = self.item.cache['durations'] for key in ('title', 'director', 'year', 'videoRatio'): - value = self.item.json.get(key) + value = self.item.cache.get(key) if value: data[key] = value data['duration'] = data['out'] - data['in'] diff --git a/pandora/document/migrations/0011_jsonfield.py b/pandora/document/migrations/0011_jsonfield.py new file mode 100644 index 00000000..166d3731 --- /dev/null +++ b/pandora/document/migrations/0011_jsonfield.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('document', '0010_auto_20170126_1528'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "document_document" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + ] diff --git a/pandora/document/models.py b/pandora/document/models.py index 8b8b8cff..c5b75fad 100644 --- a/pandora/document/models.py +++ b/pandora/document/models.py @@ -14,12 +14,12 @@ from django.contrib.auth.models import User, Group from django.db.models.signals import pre_delete from django.conf import settings from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField from PIL import Image import ox -from oxdjango import fields from oxdjango.sortmodel import get_sort_field from person.models import get_name_sort from item.models import Item @@ -65,7 +65,7 @@ class Document(models.Model): linked_documents = models.ManyToManyField('Document', related_name='linking_documents') rightslevel = models.IntegerField(db_index=True, default=0) - data = fields.DictField(default={}) + data = JSONField(default=dict, editable=False) def update_access(self, user): if not user.is_authenticated(): @@ -584,7 +584,7 @@ class Document(models.Model): def referenced(self): result = {} result['items'] = [ - i.get_json(keys=['id', 'title']) + i.json(keys=['id', 'title']) for i in self.items.all().order_by('sort__title') ] result['annotations'] = [ diff --git a/pandora/documentcollection/migrations/0003_jsonfield.py b/pandora/documentcollection/migrations/0003_jsonfield.py new file mode 100644 index 00000000..e00bf45c --- /dev/null +++ b/pandora/documentcollection/migrations/0003_jsonfield.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('documentcollection', '0002_collection_groups'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "documentcollection_collection" ALTER COLUMN "query" TYPE jsonb USING "query"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "documentcollection_collection" ALTER COLUMN "sort" TYPE jsonb USING "sort"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "documentcollection_collection" ALTER COLUMN "poster_frames" TYPE jsonb USING "poster_frames"::text::jsonb' + ), + ] diff --git a/pandora/documentcollection/models.py b/pandora/documentcollection/models.py index 3026cb7f..7a41e5d3 100644 --- a/pandora/documentcollection/models.py +++ b/pandora/documentcollection/models.py @@ -11,11 +11,10 @@ from django.db.models import Max from django.contrib.auth.models import User, Group from django.conf import settings from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField import ox -from oxdjango.fields import DictField, TupleField - from archive import extract from user.utils import update_groups @@ -47,16 +46,16 @@ class Collection(models.Model): name = models.CharField(max_length=255) status = models.CharField(max_length=20, default='private') _status = ['private', 'public', 'featured'] - query = DictField(default={"static": True}) + query = JSONField(default=lambda: {"static": True}, editable=False) type = models.CharField(max_length=255, default='static') description = models.TextField(default='') icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path) view = models.TextField(default=get_collectionview) - sort = TupleField(default=get_collectionsort, editable=False) + sort = JSONField(default=get_collectionsort, editable=False) - poster_frames = TupleField(default=[], editable=False) + poster_frames = JSONField(default=[], editable=False) #is through table still required? documents = models.ManyToManyField('document.Document', related_name='collections', diff --git a/pandora/edit/migrations/0005_jsonfield.py b/pandora/edit/migrations/0005_jsonfield.py new file mode 100644 index 00000000..745e5e33 --- /dev/null +++ b/pandora/edit/migrations/0005_jsonfield.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('edit', '0004_edit_groups'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "edit_edit" ALTER COLUMN "query" TYPE jsonb USING "query"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "edit_edit" ALTER COLUMN "poster_frames" TYPE jsonb USING "poster_frames"::text::jsonb' + ), + ] diff --git a/pandora/edit/models.py b/pandora/edit/models.py index 28ef5da5..75a6987a 100644 --- a/pandora/edit/models.py +++ b/pandora/edit/models.py @@ -10,12 +10,12 @@ import tempfile from six.moves.urllib.parse import quote import ox -from oxdjango.fields import DictField, TupleField from django.conf import settings from django.db import models, transaction from django.db.models import Max from django.contrib.auth.models import User, Group from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField from annotation.models import Annotation from item.models import Item @@ -49,12 +49,12 @@ class Edit(models.Model): description = models.TextField(default='') rightslevel = models.IntegerField(db_index=True, default=0) - query = DictField(default={"static": True}) + query = JSONField(default=lambda: {"static": True}, editable=False) type = models.CharField(max_length=255, default='static') icon = models.ImageField(default=None, blank=True, null=True, upload_to=get_icon_path) - poster_frames = TupleField(default=[], editable=False) + poster_frames = JSONField(default=[], editable=False) subscribed_users = models.ManyToManyField(User, related_name='subscribed_edits') def __str__(self): @@ -493,16 +493,16 @@ class Clip(models.Model): data['item'] = self.item.public_id data['in'] = self.annotation.start data['out'] = self.annotation.end - data['parts'] = self.annotation.item.json['parts'] - data['durations'] = self.annotation.item.json['durations'] + data['parts'] = self.annotation.item.cache['parts'] + data['durations'] = self.annotation.item.cache['durations'] else: data['item'] = self.item.public_id data['in'] = self.start data['out'] = self.end - data['parts'] = self.item.json['parts'] - data['durations'] = self.item.json['durations'] + data['parts'] = self.item.cache['parts'] + data['durations'] = self.item.cache['durations'] for key in ('title', 'director', 'year', 'videoRatio'): - value = self.item.json.get(key) + value = self.item.cache.get(key) if value: data[key] = value data['duration'] = data['out'] - data['in'] diff --git a/pandora/entity/migrations/0005_jsonfield.py b/pandora/entity/migrations/0005_jsonfield.py new file mode 100644 index 00000000..07097872 --- /dev/null +++ b/pandora/entity/migrations/0005_jsonfield.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('entity', '0004_related_name_Document_documentproperties'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "entity_entity" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "entity_documentproperties" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + ] diff --git a/pandora/entity/models.py b/pandora/entity/models.py index ad2a5fff..b094e9bf 100644 --- a/pandora/entity/models.py +++ b/pandora/entity/models.py @@ -14,6 +14,7 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete, post_init from django.conf import settings from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField import ox from oxdjango import fields @@ -40,7 +41,7 @@ class Entity(models.Model): name = models.CharField(max_length=255) alternativeNames = fields.TupleField(default=()) - data = fields.DictField(default={}, editable=False) + data = JSONField(default=dict, editable=False) matches = models.IntegerField(default=0) objects = managers.EntityManager() @@ -271,7 +272,7 @@ class DocumentProperties(models.Model): document = models.ForeignKey(Document, related_name='documentproperties') entity = models.ForeignKey(Entity, related_name='documentproperties') index = models.IntegerField(default=0) - data = fields.DictField(default={}) + data = JSONField(default=dict, editable=False) def __str__(self): return u"%r-%r" % (self.document, self.entity) diff --git a/pandora/home/migrations/0002_jsonfield.py b/pandora/home/migrations/0002_jsonfield.py new file mode 100644 index 00000000..b716fe13 --- /dev/null +++ b/pandora/home/migrations/0002_jsonfield.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('home', '0001_initial'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "home_item" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + ] diff --git a/pandora/home/models.py b/pandora/home/models.py index 2969816c..775e3714 100644 --- a/pandora/home/models.py +++ b/pandora/home/models.py @@ -8,10 +8,10 @@ from django.db import models from django.db.models import Max from django.db.models.signals import pre_delete from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField import ox -from oxdjango import fields from itemlist.models import List from edit.models import Edit from documentcollection.models import Collection @@ -24,7 +24,7 @@ class Item(models.Model): active = models.BooleanField(default=True) index = models.IntegerField(default=-1) - data = fields.DictField(default={}, editable=False) + data = JSONField(default=dict, editable=False) def editable(self, user): return user.is_authenticated() and user.profile.capability("canManageHome") diff --git a/pandora/item/migrations/0003_jsonfield.py b/pandora/item/migrations/0003_jsonfield.py new file mode 100644 index 00000000..c98fb6f8 --- /dev/null +++ b/pandora/item/migrations/0003_jsonfield.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('item', '0002_auto_20160219_1734'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "item_item" ALTER COLUMN "data" TYPE jsonb USING "data"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "item_item" ALTER COLUMN "external_data" TYPE jsonb USING "external_data"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "item_item" ALTER COLUMN "json" TYPE jsonb USING "json"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "item_item" ALTER COLUMN "stream_info" TYPE jsonb USING "stream_info"::text::jsonb' + ), + ] diff --git a/pandora/item/migrations/0004_json_cache.py b/pandora/item/migrations/0004_json_cache.py new file mode 100644 index 00000000..89962489 --- /dev/null +++ b/pandora/item/migrations/0004_json_cache.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.13 on 2018-06-19 20:24 +from __future__ import unicode_literals + +import django.core.serializers.json +from django.db import migrations, models +import oxdjango.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('item', '0003_jsonfield'), + ] + + operations = [ + migrations.RenameField( + model_name='item', + old_name='json', + new_name='cache', + ), + ] diff --git a/pandora/item/models.py b/pandora/item/models.py index 0897f5bd..7b901e5c 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -23,7 +23,7 @@ from django.utils import datetime_safe from django.utils.encoding import python_2_unicode_compatible import ox -from oxdjango import fields +from oxdjango.fields import JSONField, to_json from oxdjango.sortmodel import get_sort_field import ox.web.imdb import ox.image @@ -175,9 +175,9 @@ class Item(models.Model): public_id = models.CharField(max_length=128, unique=True, blank=True) oxdbId = models.CharField(max_length=42, unique=True, blank=True, null=True) - external_data = fields.DictField(default={}, editable=False) - data = fields.DictField(default={}, editable=False) - json = fields.DictField(default={}, editable=False) + external_data = JSONField(default=dict, editable=False) + data = JSONField(default=dict, editable=False) + cache = JSONField(default=dict, editable=False) poster = models.ImageField(default=None, blank=True, upload_to=get_poster_path) poster_source = models.TextField(blank=True) poster_height = models.IntegerField(default=0) @@ -187,7 +187,7 @@ class Item(models.Model): icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path) torrent = models.FileField(default=None, blank=True, max_length=1000, upload_to=get_torrent_path) - stream_info = fields.DictField(default={}, editable=False) + stream_info = JSONField(default=dict, editable=False) # stream related fields stream_aspect = models.FloatField(default=4/3) @@ -425,8 +425,8 @@ class Item(models.Model): self.poster_width = 80 self.update_sort() self.update_languages() - self.json = self.get_json() - self.json['modified'] = datetime.now() + self.cache = self.json() + self.cache['modified'] = datetime.now() super(Item, self).save(*args, **kwargs) self.update_find() self.update_sort() @@ -582,7 +582,7 @@ class Item(models.Model): documents = [d.json(item=self) for d in qs] return sorted(documents, key=lambda d: d['index']) - def get_json(self, keys=None): + def json(self, keys=None): i = { 'id': self.public_id, 'rendered': self.rendered, @@ -700,7 +700,7 @@ class Item(models.Model): def get_item_description_html(self): description = '' - data = self.get_json() + data = self.json() info = [] for key in [ 'director', 'writer', 'producer', @@ -1360,7 +1360,7 @@ class Item(models.Model): if offset: self.data['volume'] /= offset # extract.timeline_strip(self, self.data['cuts'], stream.info, self.timeline_prefix[:-8]) - self.json = self.get_json() + self.cache = self.json() self.update_sort() self.select_frame() self.make_poster() @@ -1375,6 +1375,10 @@ class Item(models.Model): get_sequences(self.public_id) tasks.load_subtitles.delay(self.public_id) + def update_cache(self, **kwargs): + self.cache = self.json() + Item.objects.filter(id=self.id).update(cache=self.cache, **kwargs) + def save_poster(self, data): self.poster.name = self.path('poster.jpg') poster = self.poster.path @@ -1383,11 +1387,9 @@ class Item(models.Model): self.poster_height = self.poster.height self.poster_width = self.poster.width self.clear_poster_cache(self.poster.path) - if self.json.get('posterRatio') != self.poster_width / self.poster_height: - self.json = self.get_json() - Item.objects.filter(id=self.id).update(json=self.json, - poster_width=self.poster_width, - poster_height=self.poster_height) + if self.cache.get('posterRatio') != self.poster_width / self.poster_height: + self.update_cache(poster_width=self.poster_width, + poster_height=self.poster_height) def prefered_poster_url(self): if settings.DATA_SERVICE: @@ -1467,7 +1469,7 @@ class Item(models.Model): timeline = audio_timeline cmd = [settings.ITEM_POSTER, '-d', '-', '-p', poster] - data = self.json.copy() + data = self.cache.copy() if frame: data['frame'] = frame if os.path.exists(timeline): @@ -1476,7 +1478,7 @@ class Item(models.Model): data = utils.normalize_dict('NFC', data) ox.makedirs(os.path.join(settings.MEDIA_ROOT, self.path())) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, close_fds=True) - p.communicate(json.dumps(data, default=fields.to_json).encode('utf-8')) + p.communicate(json.dumps(data, default=to_json).encode('utf-8')) self.clear_poster_cache(poster) return poster @@ -1495,8 +1497,8 @@ class Item(models.Model): }) offset += f.duration else: - if 'videoRatio' in self.json and self.sort.duration and self.streams(): - width, height = self.json['resolution'] + if 'videoRatio' in self.cache and self.sort.duration and self.streams(): + width, height = self.cache['resolution'] if width and height: pos = self.sort.duration / 2 for p in [pos/2, pos, pos+pos/2]: @@ -1636,9 +1638,9 @@ class Item(models.Model): for data in s.srt(offset): subtitles_added = True value = data['value'].replace('\n', '
\n').replace('

\n', '
\n') - if data['in'] < self.json['duration'] and data['out'] > self.json['duration']: - data['out'] = self.json['duration'] - if data['in'] < self.json['duration']: + if data['in'] < self.cache['duration'] and data['out'] > self.cache['duration']: + data['out'] = self.cache['duration'] + if data['in'] < self.cache['duration']: new.append((float('%0.03f' % data['in']), float('%0.03f' % data['out']), value)) # otherwise add empty 5 seconds annotation every minute if not subtitles_added: diff --git a/pandora/item/views.py b/pandora/item/views.py index 07d9f4b8..41d475de 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -175,11 +175,11 @@ def only_p_sums(request, query, m): if p == 'accessed': r[p] = m.sort.accessed or '' elif p == 'editable': - r[p] = is_editable(request, m.json) + r[p] = is_editable(request, m.cache) elif p in item_sort_keys: r[p] = getattr(m.sort, p) else: - r[p] = m.json.get(p) + r[p] = m.cache.get(p) if 'clip_qs' in query: r['clips'] = get_clips(query, query['clip_qs'].filter(item=m)) return r @@ -207,12 +207,12 @@ def get_items(request, query): items = [] qs = _order_query(query['qs'], query['sort']) qs = qs[query['range'][0]:query['range'][1]] - # items = [m.get_json(_p) for m in qs] + # items = [m.json(_p) for m in qs] if any(p for p in query['keys'] if p in item_sort_keys): qs = qs.select_related() items = [only_p_sums(request, query, m) for m in qs] else: - items = [only_p(request, query, m['json']) for m in qs.values('json')] + items = [only_p(request, query, m['cache']) for m in qs.values('cache')] return items def get_stats(request, query): @@ -415,7 +415,7 @@ def findId(request, data): qs = models.Item.objects.filter(public_id=data['id']) if qs.count() == 1: response['data']['items'] = [ - i.get_json(['title', 'director', 'year', 'id']) for i in qs + i.json(['title', 'director', 'year', 'id']) for i in qs ] if not response['data']['items'] \ @@ -509,7 +509,7 @@ def get(request, data): data['keys'] = data.get('keys', []) item = get_object_or_404_json(models.Item, public_id=data['id']) if item.access(request.user): - info = item.get_json(data['keys']) + info = item.json(data['keys']) if not data['keys'] or 'stream' in data['keys']: info['stream'] = item.get_stream() if not data['keys'] or 'streams' in data['keys']: @@ -602,7 +602,7 @@ def add(request, data): del data['title'] if data: response = edit_item(request, item, data) - response['data'] = item.get_json() + response['data'] = item.json() add_changelog(request, request_data, item.public_id) return render_to_json_response(response) actions.register(add, cache=False) @@ -626,7 +626,7 @@ def edit(request, data): if item.editable(request.user): request_data = data.copy() response = edit_item(request, item, data) - response['data'] = item.get_json() + response['data'] = item.json() add_changelog(request, request_data) else: response = json_response(status=403, text='permission denied') @@ -881,7 +881,7 @@ def poster(request, id, size=None): poster_height=item.poster_height, poster_width=item.poster_width, icon=item.icon.name, - json=item.get_json() + json=item.json() ) if item.poster and os.path.exists(item.poster.path): return image_to_response(item.poster, size) @@ -1040,7 +1040,7 @@ def video(request, id, resolution, format, index=None, track=None): if not r: return HttpResponseForbidden() path = video.name - duration = sum(item.json['durations']) + duration = sum(item.cache['durations']) content_type = mimetypes.guess_type(path)[0] if len(t) == 2 and t[1] > t[0] and duration >= t[1]: @@ -1304,7 +1304,7 @@ def item_json(request, id): response = json_response(status=404, text='not found') else: item = qs[0] - response = item.get_json() + response = item.json() response['layers'] = item.get_layers(request.user) return render_to_json_response(response) @@ -1318,7 +1318,7 @@ def item_xml(request, id): response = render_to_json_response(response) else: item = qs[0] - j = item.get_json() + j = item.json() j['layers'] = item.get_layers(request.user) if 'resolution' in j: j['resolution'] = {'width': j['resolution'][0], 'height': j['resolution'][1]} diff --git a/pandora/itemlist/migrations/0003_jsonfield.py b/pandora/itemlist/migrations/0003_jsonfield.py new file mode 100644 index 00000000..020c4ff8 --- /dev/null +++ b/pandora/itemlist/migrations/0003_jsonfield.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('itemlist', '0002_list_groups'), + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "itemlist_list" ALTER COLUMN "query" TYPE jsonb USING "query"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "itemlist_list" ALTER COLUMN "sort" TYPE jsonb USING "sort"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "itemlist_list" ALTER COLUMN "poster_frames" TYPE jsonb USING "poster_frames"::text::jsonb' + ), + ] diff --git a/pandora/itemlist/models.py b/pandora/itemlist/models.py index 29de3632..452aac25 100644 --- a/pandora/itemlist/models.py +++ b/pandora/itemlist/models.py @@ -11,9 +11,9 @@ from django.db.models import Max from django.contrib.auth.models import User, Group from django.conf import settings from django.utils.encoding import python_2_unicode_compatible -import ox +from oxdjango.fields import JSONField -from oxdjango.fields import DictField, TupleField +import ox from archive import extract from user.utils import update_groups @@ -39,16 +39,16 @@ class List(models.Model): name = models.CharField(max_length=255) status = models.CharField(max_length=20, default='private') _status = ['private', 'public', 'featured'] - query = DictField(default={"static": True}) + query = JSONField(default=lambda: {"static": True}, editable=False) type = models.CharField(max_length=255, default='static') description = models.TextField(default='') icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path) view = models.TextField(default=get_listview) - sort = TupleField(default=get_listsort, editable=False) + sort = JSONField(default=get_listsort, editable=False) - poster_frames = TupleField(default=[], editable=False) + poster_frames = JSONField(default=[], editable=False) #is through table still required? items = models.ManyToManyField('item.Item', related_name='lists', diff --git a/pandora/oxdjango/fields.py b/pandora/oxdjango/fields.py index fcb749bb..e4f4ae43 100644 --- a/pandora/oxdjango/fields.py +++ b/pandora/oxdjango/fields.py @@ -5,10 +5,19 @@ import copy from django.db import models from django.utils import datetime_safe +import django.contrib.postgres.fields +from django.core.serializers.json import DjangoJSONEncoder + from six import string_types from ox.utils import json +class JSONField(django.contrib.postgres.fields.JSONField): + + def __init__(self, *args, **kwargs): + if 'encoder' not in kwargs: + kwargs['encoder'] = DjangoJSONEncoder + super().__init__(*args, **kwargs) def to_json(python_object): if isinstance(python_object, datetime.datetime): diff --git a/pandora/sequence/models.py b/pandora/sequence/models.py index 9abc6846..2970c3f2 100644 --- a/pandora/sequence/models.py +++ b/pandora/sequence/models.py @@ -55,5 +55,5 @@ class Sequence(models.Model): if keys: for key in keys: if key not in j: - j[key] = self.sort.item.json.get(key) + j[key] = self.sort.item.cache.get(key) return j diff --git a/pandora/tv/models.py b/pandora/tv/models.py index 3669df7b..6a68d214 100644 --- a/pandora/tv/models.py +++ b/pandora/tv/models.py @@ -87,7 +87,7 @@ class Program(models.Model): return u"%s %s" % (self.item, self.start) def json(self, user, current=False): - item_json = self.item.get_json() + item_json = self.item.json() r = { 'item': self.item.public_id, } diff --git a/pandora/user/migrations/0004_jsonfield.py b/pandora/user/migrations/0004_jsonfield.py new file mode 100644 index 00000000..90a5548a --- /dev/null +++ b/pandora/user/migrations/0004_jsonfield.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2018-06-19 17:23 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0003_sessiondata_numberofcollections') + ] + + operations = [ + migrations.RunSQL( + 'ALTER TABLE "user_sessiondata" ALTER COLUMN "info" TYPE jsonb USING "info"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "user_userprofile" ALTER COLUMN "ui" TYPE jsonb USING "ui"::text::jsonb' + ), + migrations.RunSQL( + 'ALTER TABLE "user_userprofile" ALTER COLUMN "preferences" TYPE jsonb USING "preferences"::text::jsonb' + ), + ] diff --git a/pandora/user/models.py b/pandora/user/models.py index 6c7208eb..7994651c 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -9,9 +9,9 @@ from django.db import models from django.db.models import Max from django.conf import settings from django.utils.encoding import python_2_unicode_compatible +from oxdjango.fields import JSONField import ox -from oxdjango.fields import DictField from ox.utils import json from itemlist.models import List, Position @@ -38,7 +38,7 @@ class SessionData(models.Model): useragent = models.CharField(max_length=4096, null=True) windowsize = models.CharField(max_length=255, null=True) screensize = models.CharField(max_length=255, null=True) - info = DictField(default={}) + info = JSONField(default=dict, editable=False) location = models.CharField(max_length=255, null=True) location_sort = models.CharField(max_length=255, null=True) @@ -178,8 +178,8 @@ class UserProfile(models.Model): level = models.IntegerField(default=1) files_updated = models.DateTimeField(default=datetime.now) newsletter = models.BooleanField(default=True) - ui = DictField(default={}) - preferences = DictField(default={}) + ui = JSONField(default=dict, editable=False) + preferences = JSONField(default=dict, editable=False) notes = models.TextField(default='') diff --git a/requirements.txt b/requirements.txt index d26eb648..4370f871 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,12 @@ -Django==1.9.4 +Django==1.11.13 simplejson chardet -celery==3.1.23 -django-celery==3.1.17 -django-extensions==1.6.1 -gunicorn==19.4.5 +celery==3.1.26.post2 +django-celery==3.2.2 +django-extensions==2.0.7 +gunicorn==19.8.1 html5lib -requests==2.9.1 -tornado==4.1 -geoip2==2.2.0 +requests==2.19.1 +tornado==5.0.2 +geoip2==2.9.0 youtube-dl diff --git a/update.py b/update.py index 9f961819..136f10e3 100755 --- a/update.py +++ b/update.py @@ -247,6 +247,8 @@ if __name__ == "__main__": run('./bin/pip', 'install', '-r', 'requirements.txt') update_service('pandora-encoding') update_service('pandora-tasks') + if old < 5972: + run('./bin/pip', 'install', '-r', 'requirements.txt') else: if len(sys.argv) == 1: release = get_release()