From 55656e2d3d84f51b6e9c76d2dbf2f33921de47d7 Mon Sep 17 00:00:00 2001
From: Ed Summers
Date: Mon, 19 Dec 2011 01:33:13 -0500
Subject: [PATCH] now getting subjects from openlibrary instead of from
googlebooks. You will need to APPLY MIGRATIONS!
---
core/bookloader.py | 47 +++-
core/goodreads.py | 7 +-
core/librarything.py | 3 +-
core/management/commands/add_related.py | 13 --
core/migrations/0013_move_subject_to_work.py | 220 ++++++++++++++++++
core/migrations/0014_populate_subjects.py | 202 ++++++++++++++++
...d_subject_name__add_unique_subject_name.py | 210 +++++++++++++++++
...auto__add_field_work_openlibrary_lookup.py | 205 ++++++++++++++++
core/models.py | 5 +-
core/tasks.py | 21 +-
core/tests.py | 39 ++--
experimental/matcher.py | 16 +-
experimental/zotero_books.py | 4 +-
frontend/templates/subjects.html | 4 +-
frontend/views.py | 23 +-
15 files changed, 945 insertions(+), 74 deletions(-)
delete mode 100644 core/management/commands/add_related.py
create mode 100644 core/migrations/0013_move_subject_to_work.py
create mode 100644 core/migrations/0014_populate_subjects.py
create mode 100644 core/migrations/0015_auto__chg_field_subject_name__add_unique_subject_name.py
create mode 100644 core/migrations/0016_auto__add_field_work_openlibrary_lookup.py
diff --git a/core/bookloader.py b/core/bookloader.py
index f13b1bbc..36f3177e 100755
--- a/core/bookloader.py
+++ b/core/bookloader.py
@@ -1,5 +1,6 @@
import json
import logging
+import datetime
import requests
from xml.etree import ElementTree
@@ -12,6 +13,7 @@ from regluit.core import models
logger = logging.getLogger(__name__)
+
def add_by_oclc(oclc):
logger.info("adding book by oclc %s", oclc)
for edition in models.Edition.objects.filter(oclc=oclc):
@@ -107,10 +109,6 @@ def add_by_googlebooks_id(googlebooks_id, work=None):
a, created = models.Author.objects.get_or_create(name=a)
a.editions.add(e)
- for s in d.get('categories', []):
- s, created = models.Subject.objects.get_or_create(name=s)
- s.editions.add(e)
-
access_info = item.get('accessInfo')
if access_info:
e.public_domain = item.get('public_domain', None)
@@ -192,6 +190,47 @@ def merge_works(w1, w2):
w2.delete()
+def add_openlibrary(work):
+ work.openlibrary_lookup = datetime.datetime.now()
+ work.save()
+
+ # find the first ISBN match in OpenLibrary
+ logger.info("looking up openlibrary data for work %s", work.id)
+ found = False
+ e = None # openlibrary edition json
+ w = None # openlibrary work json
+
+ # get the 1st openlibrary match by isbn that has an associated work
+ url = "http://openlibrary.org/api/books"
+ params = {"format": "json", "jscmd": "details"}
+ for edition in work.editions.all():
+ isbn_key = "ISBN:%s" % edition.isbn_10
+ params['bibkeys'] = isbn_key
+ e = _get_json(url, params)
+ if e.has_key(isbn_key) and e[isbn_key]['details'].has_key('works'):
+ work_key = e[isbn_key]['details']['works'].pop(0)['key']
+ logger.info("got openlibrary work %s for isbn %s", work_key, isbn_key)
+ w = _get_json("http://openlibrary.org" + work_key)
+ if w.has_key('subjects'):
+ found = True
+ break
+
+ if not found:
+ logger.warn("unable to find work %s at openlibrary", work.id)
+ return
+
+ # add the subjects to the Work
+ for s in w.get('subjects', []):
+ logger.info("adding subject %s to work %s", s, work.id)
+ subject, created = models.Subject.objects.get_or_create(name=s)
+ work.subjects.add(subject)
+
+ work.openlibrary_id = w['key']
+ work.save()
+ # TODO: add authors here once they are moved from Edition to Work
+ # TODO: add LCCN, LibraryThing, GoodReads to appropriate models
+
+
def _get_json(url, params={}):
# TODO: should X-Forwarded-For change based on the request from client?
headers = {'User-Agent': settings.USER_AGENT,
diff --git a/core/goodreads.py b/core/goodreads.py
index bf9985ee..b7d56b96 100644
--- a/core/goodreads.py
+++ b/core/goodreads.py
@@ -285,13 +285,12 @@ def load_goodreads_shelf_into_wishlist(user, shelf_name='all', goodreads_user_id
if match:
edition.goodreads_id = match.group(1)
edition.save()
+ regluit.core.tasks.populate_edition.delay(edition)
+ user.wishlist.add_work(edition.work, 'goodreads')
+ logger.info("Work with isbn %s added to wishlist.", isbn)
else:
logger.error("unable to extract goodreads id from %s", link)
- # let's not trigger too much traffic to Google books for now
- # regluit.core.tasks.add_related.delay(isbn)
- user.wishlist.add_work(edition.work, 'goodreads')
- logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
logger.info ("Exception adding ISBN %s: %s", isbn, e)
diff --git a/core/librarything.py b/core/librarything.py
index 644e092b..4330ce19 100644
--- a/core/librarything.py
+++ b/core/librarything.py
@@ -217,8 +217,7 @@ def load_librarything_into_wishlist(user, lt_username, max_books=None):
edition.work.librarything_id = book['work_id']
edition.work.save()
- # let's not trigger too much traffic to Google books for now
- # regluit.core.tasks.add_related.delay(isbn)
+ regluit.core.tasks.populate_edition.delay(edition)
user.wishlist.add_work(edition.work, 'librarything')
logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
diff --git a/core/management/commands/add_related.py b/core/management/commands/add_related.py
deleted file mode 100644
index f71403d5..00000000
--- a/core/management/commands/add_related.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from django.core.management.base import BaseCommand
-
-from regluit.core import tasks, models
-
-class Command(BaseCommand):
- help = "queues add related books for works that have only one edition"
-
- def handle(self, **options):
- for work in models.Work.objects.all():
- if work.editions.all().count() == 1:
- sole_edition = work.editions.all()[0]
- tasks.add_related.delay(sole_edition.isbn_10)
-
diff --git a/core/migrations/0013_move_subject_to_work.py b/core/migrations/0013_move_subject_to_work.py
new file mode 100644
index 00000000..3daca22e
--- /dev/null
+++ b/core/migrations/0013_move_subject_to_work.py
@@ -0,0 +1,220 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Removing M2M table for field editions on 'Subject'
+ db.delete_table('core_subject_editions')
+
+ # Adding M2M table for field works on 'Subject'
+ db.create_table('core_subject_works', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('subject', models.ForeignKey(orm['core.subject'], null=False)),
+ ('work', models.ForeignKey(orm['core.work'], null=False))
+ ))
+ db.create_unique('core_subject_works', ['subject_id', 'work_id'])
+
+
+ def backwards(self, orm):
+
+ # Adding M2M table for field editions on 'Subject'
+ db.create_table('core_subject_editions', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('subject', models.ForeignKey(orm['core.subject'], null=False)),
+ ('edition', models.ForeignKey(orm['core.edition'], null=False))
+ ))
+ db.create_unique('core_subject_editions', ['subject_id', 'edition_id'])
+
+ # Removing M2M table for field works on 'Subject'
+ db.delete_table('core_subject_works')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'core.author': {
+ 'Meta': {'object_name': 'Author'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'core.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'deadline': ('django.db.models.fields.DateTimeField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+ 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}),
+ 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
+ },
+ 'core.campaignaction': {
+ 'Meta': {'object_name': 'CampaignAction'},
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'})
+ },
+ 'core.celerytask': {
+ 'Meta': {'object_name': 'CeleryTask'},
+ 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2011, 12, 15, 22, 25, 4, 967842)', 'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.claim': {
+ 'Meta': {'object_name': 'Claim'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"})
+ },
+ 'core.ebook': {
+ 'Meta': {'object_name': 'Ebook'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}),
+ 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'core.edition': {
+ 'Meta': {'object_name': 'Edition'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
+ 'goodreads_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
+ 'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'oclc': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True'}),
+ 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
+ },
+ 'core.premium': {
+ 'Meta': {'object_name': 'Premium'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'})
+ },
+ 'core.rightsholder': {
+ 'Meta': {'object_name': 'RightsHolder'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}),
+ 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'core.subject': {
+ 'Meta': {'object_name': 'Subject'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
+ },
+ 'core.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+ 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
+ 'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.wishes': {
+ 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"})
+ },
+ 'core.wishlist': {
+ 'Meta': {'object_name': 'Wishlist'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"})
+ },
+ 'core.work': {
+ 'Meta': {'ordering': "['title']", 'object_name': 'Work'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
+ }
+ }
+
+ complete_apps = ['core']
diff --git a/core/migrations/0014_populate_subjects.py b/core/migrations/0014_populate_subjects.py
new file mode 100644
index 00000000..39be1191
--- /dev/null
+++ b/core/migrations/0014_populate_subjects.py
@@ -0,0 +1,202 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+from regluit.core import bookloader
+from regluit.core.models import Work
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ for w in Work.objects.all():
+ bookloader.add_subjects(w)
+
+ def backwards(self, orm):
+ pass
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'core.author': {
+ 'Meta': {'object_name': 'Author'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'core.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'deadline': ('django.db.models.fields.DateTimeField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+ 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}),
+ 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
+ },
+ 'core.campaignaction': {
+ 'Meta': {'object_name': 'CampaignAction'},
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'})
+ },
+ 'core.celerytask': {
+ 'Meta': {'object_name': 'CeleryTask'},
+ 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2011, 12, 18, 23, 27, 58, 39040)', 'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.claim': {
+ 'Meta': {'object_name': 'Claim'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"})
+ },
+ 'core.ebook': {
+ 'Meta': {'object_name': 'Ebook'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}),
+ 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'core.edition': {
+ 'Meta': {'object_name': 'Edition'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
+ 'goodreads_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
+ 'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'oclc': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True'}),
+ 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
+ },
+ 'core.premium': {
+ 'Meta': {'object_name': 'Premium'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'})
+ },
+ 'core.rightsholder': {
+ 'Meta': {'object_name': 'RightsHolder'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}),
+ 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'core.subject': {
+ 'Meta': {'object_name': 'Subject'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
+ },
+ 'core.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+ 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
+ 'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.wishes': {
+ 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"})
+ },
+ 'core.wishlist': {
+ 'Meta': {'object_name': 'Wishlist'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"})
+ },
+ 'core.work': {
+ 'Meta': {'ordering': "['title']", 'object_name': 'Work'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
+ }
+ }
+
+ complete_apps = ['core']
diff --git a/core/migrations/0015_auto__chg_field_subject_name__add_unique_subject_name.py b/core/migrations/0015_auto__chg_field_subject_name__add_unique_subject_name.py
new file mode 100644
index 00000000..aa446e7b
--- /dev/null
+++ b/core/migrations/0015_auto__chg_field_subject_name__add_unique_subject_name.py
@@ -0,0 +1,210 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'Subject.name'
+ db.alter_column('core_subject', 'name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200))
+
+ # Adding unique constraint on 'Subject', fields ['name']
+ db.create_unique('core_subject', ['name'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'Subject', fields ['name']
+ db.delete_unique('core_subject', ['name'])
+
+ # Changing field 'Subject.name'
+ db.alter_column('core_subject', 'name', self.gf('django.db.models.fields.CharField')(max_length=500))
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'core.author': {
+ 'Meta': {'object_name': 'Author'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'core.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'deadline': ('django.db.models.fields.DateTimeField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+ 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}),
+ 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
+ },
+ 'core.campaignaction': {
+ 'Meta': {'object_name': 'CampaignAction'},
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'})
+ },
+ 'core.celerytask': {
+ 'Meta': {'object_name': 'CeleryTask'},
+ 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2011, 12, 19, 1, 15, 14, 636254)', 'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.claim': {
+ 'Meta': {'object_name': 'Claim'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"})
+ },
+ 'core.ebook': {
+ 'Meta': {'object_name': 'Ebook'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}),
+ 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'core.edition': {
+ 'Meta': {'object_name': 'Edition'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
+ 'goodreads_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
+ 'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'oclc': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True'}),
+ 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
+ },
+ 'core.premium': {
+ 'Meta': {'object_name': 'Premium'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'})
+ },
+ 'core.rightsholder': {
+ 'Meta': {'object_name': 'RightsHolder'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}),
+ 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'core.subject': {
+ 'Meta': {'object_name': 'Subject'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
+ },
+ 'core.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+ 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
+ 'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.wishes': {
+ 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"})
+ },
+ 'core.wishlist': {
+ 'Meta': {'object_name': 'Wishlist'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"})
+ },
+ 'core.work': {
+ 'Meta': {'ordering': "['title']", 'object_name': 'Work'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
+ }
+ }
+
+ complete_apps = ['core']
diff --git a/core/migrations/0016_auto__add_field_work_openlibrary_lookup.py b/core/migrations/0016_auto__add_field_work_openlibrary_lookup.py
new file mode 100644
index 00000000..165f17a5
--- /dev/null
+++ b/core/migrations/0016_auto__add_field_work_openlibrary_lookup.py
@@ -0,0 +1,205 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Work.openlibrary_lookup'
+ db.add_column('core_work', 'openlibrary_lookup', self.gf('django.db.models.fields.DateTimeField')(null=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Work.openlibrary_lookup'
+ db.delete_column('core_work', 'openlibrary_lookup')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'core.author': {
+ 'Meta': {'object_name': 'Author'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'core.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'deadline': ('django.db.models.fields.DateTimeField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+ 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}),
+ 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
+ },
+ 'core.campaignaction': {
+ 'Meta': {'object_name': 'CampaignAction'},
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'})
+ },
+ 'core.celerytask': {
+ 'Meta': {'object_name': 'CeleryTask'},
+ 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2011, 12, 19, 1, 22, 42, 254688)', 'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.claim': {
+ 'Meta': {'object_name': 'Claim'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"})
+ },
+ 'core.ebook': {
+ 'Meta': {'object_name': 'Ebook'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}),
+ 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'core.edition': {
+ 'Meta': {'object_name': 'Edition'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
+ 'goodreads_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
+ 'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'oclc': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True'}),
+ 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
+ },
+ 'core.premium': {
+ 'Meta': {'object_name': 'Premium'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'})
+ },
+ 'core.rightsholder': {
+ 'Meta': {'object_name': 'RightsHolder'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}),
+ 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'core.subject': {
+ 'Meta': {'object_name': 'Subject'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
+ },
+ 'core.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+ 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
+ 'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+ },
+ 'core.wishes': {
+ 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"})
+ },
+ 'core.wishlist': {
+ 'Meta': {'object_name': 'Wishlist'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"})
+ },
+ 'core.work': {
+ 'Meta': {'ordering': "['title']", 'object_name': 'Work'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}),
+ 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'openlibrary_lookup': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
+ }
+ }
+
+ complete_apps = ['core']
diff --git a/core/models.py b/core/models.py
index 1963f5e9..def5dd3d 100755
--- a/core/models.py
+++ b/core/models.py
@@ -211,6 +211,7 @@ class Work(models.Model):
openlibrary_id = models.CharField(max_length=50, null=True)
librarything_id = models.CharField(max_length=50, null=True)
language = models.CharField(max_length=2, default="en", null=False)
+ openlibrary_lookup = models.DateTimeField(null=True)
class Meta:
ordering = ['title']
@@ -366,8 +367,8 @@ class Author(models.Model):
class Subject(models.Model):
created = models.DateTimeField(auto_now_add=True)
- name = models.CharField(max_length=500)
- editions = models.ManyToManyField("Edition", related_name="subjects")
+ name = models.CharField(max_length=200, unique=True)
+ works = models.ManyToManyField("Work", related_name="subjects")
def __unicode__(self):
return self.name
diff --git a/core/tasks.py b/core/tasks.py
index fa974d49..9c2a5394 100644
--- a/core/tasks.py
+++ b/core/tasks.py
@@ -1,15 +1,18 @@
-from celery.decorators import task
-from regluit.core import bookloader
-from regluit.core import goodreads, librarything
from time import sleep
-@task
-def add_related(isbn):
- return bookloader.add_related(isbn)
+from celery.decorators import task
-@task
-def add_by_isbn(isbn):
- return bookloader.add_by_isbn(isbn)
+from regluit.core import bookloader
+from regluit.core import goodreads, librarything
+
+@task
+def populate_edition(edition):
+ """given an edition this task will populate the database with additional
+ information about related editions and subjects related to this edition
+ """
+ bookloader.add_related(edition.isbn_10)
+ bookloader.add_openlibrary(edition.work)
+ return edition
@task
def load_goodreads_shelf_into_wishlist(user, shelf_name='all', goodreads_user_id=None, max_books=None,
diff --git a/core/tests.py b/core/tests.py
index 28ce35ce..aa76c344 100755
--- a/core/tests.py
+++ b/core/tests.py
@@ -21,7 +21,7 @@ from time import sleep
from math import factorial
-class TestBookLoader(TestCase):
+class BookLoaderTests(TestCase):
def test_add_by_isbn(self):
# edition
@@ -33,11 +33,6 @@ class TestBookLoader(TestCase):
self.assertEqual(edition.isbn_13, '9780441012039')
self.assertEqual(edition.googlebooks_id, "2NyiPwAACAAJ")
- # subjects
- subject_names = [subject.name for subject in edition.subjects.all()]
- self.assertEqual(len(subject_names), 11)
- self.assertTrue('Japan' in subject_names)
-
# authors
self.assertEqual(edition.authors.all().count(), 1)
self.assertEqual(edition.authors.all()[0].name, 'William Gibson')
@@ -51,7 +46,6 @@ class TestBookLoader(TestCase):
self.assertEqual(models.Edition.objects.all().count(), 1)
self.assertEqual(models.Author.objects.all().count(), 1)
self.assertEqual(models.Work.objects.all().count(), 1)
- self.assertEqual(models.Subject.objects.all().count(), 11)
def test_missing_isbn(self):
e = bookloader.add_by_isbn('0139391401')
@@ -79,6 +73,11 @@ class TestBookLoader(TestCase):
self.assertEqual(models.Edition.objects.count(),
edition.work.editions.count())
+ def test_populate_edition(self):
+ edition = bookloader.add_by_googlebooks_id('c_dBPgAACAAJ')
+ edition = tasks.populate_edition.run(edition)
+ self.assertTrue(edition.work.editions.all().count() > 20)
+ self.assertTrue(edition.work.subjects.all().count() > 10)
def test_merge_works(self):
# add two editions and see that there are two stub works
@@ -86,6 +85,8 @@ class TestBookLoader(TestCase):
e2 = bookloader.add_by_isbn('1458776204')
self.assertTrue(e1)
self.assertTrue(e2)
+ self.assertTrue(e1.work)
+ self.assertTrue(e2.work)
self.assertEqual(models.Work.objects.count(), 2)
# add the stub works to a wishlist
@@ -117,10 +118,6 @@ class TestBookLoader(TestCase):
self.assertEqual(c1.work, c2.work)
self.assertEqual(user.wishlist.works.all().count(), 1)
- def test_oclc(self):
- edition = bookloader.add_by_oclc('1246014')
- self.assertEqual(edition.title, 'The Latin language')
-
def test_ebook(self):
edition = bookloader.add_by_oclc('1246014')
self.assertEqual(edition.ebooks.count(), 2)
@@ -154,6 +151,19 @@ class TestBookLoader(TestCase):
for edition in work.editions.all():
self.assertEqual(edition.title.lower(), "cat's cradle")
+ def test_add_openlibrary(self):
+ work = bookloader.add_by_isbn('0441012035').work
+ bookloader.add_related('0441012035')
+ bookloader.add_openlibrary(work)
+ subjects = work.subjects.all()
+ for s in work.subjects.all():
+ print s.name
+ self.assertEqual(len(subjects), 2)
+ self.assertEqual(subjects[0].name, 'Computer science')
+ self.assertEqual(subjects[1].name, 'Mathematics')
+ self.assertEqual(work.openlibrary_id, '/works/OL3951639W')
+
+
class SearchTests(TestCase):
def test_basic_search(self):
@@ -384,10 +394,3 @@ class ISBNTest(TestCase):
self.assertEqual(len(set([str(isbn.ISBN(milosz_10)), str(isbn.ISBN(milosz_13))])),2)
self.assertEqual(len(set([isbn.ISBN(milosz_10).to_string(), isbn.ISBN(milosz_13).to_string()])),1)
-def suite():
-
- testcases = [TestBookLoader, SearchTests, CampaignTests, WishlistTest, CeleryTaskTest, GoodreadsTest, LibraryThingTest, ISBNTest]
- suites = unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(testcase) for testcase in testcases])
- suites.addTest(SettingsTest('test_dev_me_alignment')) # give option to test this alignment
- return suites
-
diff --git a/experimental/matcher.py b/experimental/matcher.py
index 83c454a0..779acefb 100755
--- a/experimental/matcher.py
+++ b/experimental/matcher.py
@@ -2,12 +2,16 @@
import re
import json
-import time
-import urllib
+import fileinput
import requests
-from oaipmh.client import Client
-from oaipmh.metadata import MetadataRegistry, oai_dc_reader
+
+def match():
+ for line in fileinput.input():
+ j = json.loads(line)
+ authors = j['authors']
+ title = j['title']
+ print googlebooks_id(title, authors)
def google_search(title, authors, no_matches):
headers = {'X-Forwarded-For': '69.243.24.29'}
@@ -78,6 +82,4 @@ def norm_author(a):
return a
if __name__ == "__main__":
- results = open("results.txt", "w")
- no_matches = open("no-matches.log", "w")
- lookup(results, no_matches)
+ googlebooks_ids()
diff --git a/experimental/zotero_books.py b/experimental/zotero_books.py
index a2078115..43b4511a 100644
--- a/experimental/zotero_books.py
+++ b/experimental/zotero_books.py
@@ -101,7 +101,7 @@ class MyZotero(Zotero2):
if isbn:
edition = bookloader.add_by_isbn(isbn)
# let's not trigger too much traffic to Google books for now
- # regluit.core.tasks.add_related.delay(isbn)
+ regluit.core.tasks.populate_edition.delay(edition)
user.wishlist.add_work(edition.work, 'zotero')
logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
@@ -116,4 +116,4 @@ if __name__ == '__main__':
for (i,b) in enumerate(zot.get_books(300)):
print b
#zot.upload_to_unglue_it('RaymondYee',5000)
- #print zot.get_all_items()
\ No newline at end of file
+ #print zot.get_all_items()
diff --git a/frontend/templates/subjects.html b/frontend/templates/subjects.html
index 97aa951f..e0390b80 100644
--- a/frontend/templates/subjects.html
+++ b/frontend/templates/subjects.html
@@ -10,14 +10,14 @@
wishlists. It is here primarily to show what subjects are present
in the database to guide further development. You can order by the
subject name or by the
- number of editions
+ number of works
with that subject.
{% for subject in subjects %}
- - {{ subject.name }} ({{ subject.editions__count }})
+ - {{ subject.name }} ({{ subject.works__count }})
{% endfor %}
diff --git a/frontend/views.py b/frontend/views.py
index c2b97142..cc6f2abc 100755
--- a/frontend/views.py
+++ b/frontend/views.py
@@ -4,9 +4,12 @@ import json
import urllib
import logging
import datetime
-from decimal import Decimal as D
from re import sub
+from itertools import islice
+from decimal import Decimal as D
+import requests
+import oauth2 as oauth
from django import forms
from django.db.models import Q, Count, Sum
from django.conf import settings
@@ -26,10 +29,6 @@ from django.contrib.auth.decorators import login_required
from django.shortcuts import render, render_to_response, get_object_or_404
from django.utils.translation import ugettext_lazy as _
-import requests
-import oauth2 as oauth
-from itertools import islice
-
from regluit.core import tasks
from regluit.core import models, bookloader, librarything
from regluit.core import userlists
@@ -40,13 +39,13 @@ from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThin
from regluit.frontend.forms import ManageCampaignForm, DonateForm
from regluit.payment.manager import PaymentManager
from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN, TARGET_TYPE_DONATION
-
from regluit.core import goodreads
from tastypie.models import ApiKey
+from regluit.payment.models import Transaction
+
logger = logging.getLogger(__name__)
-from regluit.payment.models import Transaction
def home(request):
if request.user.is_authenticated():
@@ -136,19 +135,21 @@ def googlebooks(request, googlebooks_id):
edition = models.Edition.objects.get(googlebooks_id=googlebooks_id)
except models.Edition.DoesNotExist:
edition = bookloader.add_by_googlebooks_id(googlebooks_id)
+ # we could populate_edition(edition) to pull in related editions here
+ # but it is left out for now to lower the amount of traffic on
+ # googlebooks, librarything and openlibrary
if not edition:
return HttpResponseNotFound("invalid googlebooks id")
- tasks.add_related.delay(edition.isbn_10)
work_url = reverse('work', kwargs={'work_id': edition.work.id})
return HttpResponseRedirect(work_url)
def subjects(request):
order = request.GET.get('order')
subjects = models.Subject.objects.all()
- subjects = subjects.annotate(Count('editions'))
+ subjects = subjects.annotate(Count('works'))
if request.GET.get('order') == 'count':
- subjects = subjects.order_by('-editions__count')
+ subjects = subjects.order_by('-works__count')
else:
subjects = subjects.order_by('name')
@@ -558,7 +559,7 @@ def wishlist(request):
if googlebooks_id:
edition = bookloader.add_by_googlebooks_id(googlebooks_id)
# add related editions asynchronously
- tasks.add_related.delay(edition.isbn_10)
+ tasks.populate_edition.delay(edition)
request.user.wishlist.add_work(edition.work,'user')
# TODO: redirect to work page, when it exists
return HttpResponseRedirect('/')