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()