1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Maintain registry of documents used in your django project
19 and manage db sessions
20 """
21
22 import sys
23 import os
24
25 from restkit import BasicAuth
26 from couchdbkit import Server
27 from couchdbkit import push
28 from couchdbkit.resource import CouchdbResource
29 from couchdbkit.exceptions import ResourceNotFound
30 from django.conf import settings
31 from django.utils.datastructures import SortedDict
32
33 COUCHDB_DATABASES = getattr(settings, "COUCHDB_DATABASES", [])
34 COUCHDB_TIMEOUT = getattr(settings, "COUCHDB_TIMEOUT", 300)
35
37 """ The couchdbkit handler for django """
38
39
40 __shared_state__ = dict(
41 _databases = {},
42 app_schema = SortedDict()
43 )
44
46 """ initialize couchdbkit handler with COUCHDB_DATABASES
47 settings """
48
49 self.__dict__ = self.__shared_state__
50
51
52 if isinstance(databases, (list, tuple)):
53 databases = dict(
54 (app_name, {'URL': uri}) for app_name, uri in databases
55 )
56
57
58 for app_name, app_setting in databases.iteritems():
59 uri = app_setting['URL']
60
61
62 user = app_setting.get('USER', '')
63 password = app_setting.get('PASSWORD', '')
64 auth = BasicAuth(user, password)
65
66 try:
67 if isinstance(uri, (list, tuple)):
68
69
70
71 server_uri, dbname = uri
72 else:
73 server_uri, dbname = uri.rsplit("/", 1)
74 except ValueError:
75 raise ValueError("couchdb uri [%s:%s] invalid" % (
76 app_name, uri))
77
78 res = CouchdbResource(server_uri, timeout=COUCHDB_TIMEOUT, filters=[auth])
79
80 server = Server(server_uri, resource_instance=res)
81 app_label = app_name.split('.')[-1]
82 self._databases[app_label] = (server, dbname)
83
84 - def sync(self, app, verbosity=2, temp=None):
85 """ used to sync views of all applications and eventually create
86 database.
87
88 When temp is specified, it is appended to the app's name on the docid.
89 It can then be updated in the background and copied over the existing
90 design docs to reduce blocking time of view updates """
91 app_name = app.__name__.rsplit('.', 1)[0]
92 app_labels = set()
93 schema_list = self.app_schema.values()
94 for schema_dict in schema_list:
95 for schema in schema_dict.values():
96 app_module = schema.__module__.rsplit(".", 1)[0]
97 if app_module == app_name and not schema._meta.app_label in app_labels:
98 app_labels.add(schema._meta.app_label)
99 for app_label in app_labels:
100 if not app_label in self._databases:
101 continue
102 if verbosity >=1:
103 print "sync `%s` in CouchDB" % app_name
104 db = self.get_db(app_label)
105
106 app_path = os.path.abspath(os.path.join(sys.modules[app.__name__].__file__, ".."))
107 design_path = "%s/%s" % (app_path, "_design")
108 if not os.path.isdir(design_path):
109 if settings.DEBUG:
110 print >>sys.stderr, "%s don't exists, no ddoc synchronized" % design_path
111 return
112
113 if temp:
114 design_name = '%s-%s' % (app_label, temp)
115 else:
116 design_name = app_label
117
118 docid = "_design/%s" % design_name
119
120 push(os.path.join(app_path, "_design"), db, force=True,
121 docid=docid)
122
123 if temp:
124 ddoc = db[docid]
125 view_names = ddoc.get('views', {}).keys()
126 if len(view_names) > 0:
127 if verbosity >= 1:
128 print 'Triggering view rebuild'
129
130 view = '%s/%s' % (design_name, view_names[0])
131 list(db.view(view, limit=0))
132
133
134 - def copy_designs(self, app, temp, verbosity=2, delete=True):
135 """ Copies temporary view over the existing ones
136
137 This is used to reduce the waiting time for blocking view updates """
138
139 app_name = app.__name__.rsplit('.', 1)[0]
140 app_label = app_name.split('.')[-1]
141 if app_label in self._databases:
142 if verbosity >=1:
143 print "Copy prepared design docs for `%s`" % app_name
144 db = self.get_db(app_label)
145
146 tmp_name = '%s-%s' % (app_label, temp)
147
148 from_id = '_design/%s' % tmp_name
149 to_id = '_design/%s' % app_label
150
151 try:
152 db.copy_doc(from_id, to_id)
153
154 if delete:
155 del db[from_id]
156
157 except ResourceNotFound:
158 print '%s not found.' % (from_id, )
159 return
160
161
162 - def get_db(self, app_label, register=False):
163 """ retrieve db session for a django application """
164 if register:
165 return
166
167 db = self._databases[app_label]
168 if isinstance(db, tuple):
169 server, dbname = db
170 db = server.get_or_create_db(dbname)
171 self._databases[app_label] = db
172 return db
173
175 """ register a Document object"""
176 for s in schema:
177 schema_name = schema[0].__name__.lower()
178 schema_dict = self.app_schema.setdefault(app_label, SortedDict())
179 if schema_name in schema_dict:
180 fname1 = os.path.abspath(sys.modules[s.__module__].__file__)
181 fname2 = os.path.abspath(sys.modules[schema_dict[schema_name].__module__].__file__)
182 if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
183 continue
184 schema_dict[schema_name] = s
185
187 """ retriev Document object from its name and app name """
188 return self.app_schema.get(app_label, SortedDict()).get(schema_name.lower())
189
190 couchdbkit_handler = CouchdbkitHandler(COUCHDB_DATABASES)
191 register_schema = couchdbkit_handler.register_schema
192 get_schema = couchdbkit_handler.get_schema
193 get_db = couchdbkit_handler.get_db
194