def put_attachment(self, doc, content, name=None, content_type=None, content_length=None): """ Add attachement to a document. All attachments are streamed. @param doc: dict, document object @param content: string or :obj:`File` object. @param name: name or attachment (file name). @param content_type: string, mimetype of attachment. If you don't set it, it will be autodetected. @param content_lenght: int, size of attachment. @return: bool, True if everything was ok. Example: >>> from simplecouchdb import server >>> server = server() >>> db = server.create_db('couchapp_test') >>> doc = { 'string': 'test', 'number': 4 } >>> db.save(doc) >>> text_attachment = u'un texte attaché' >>> db.put_attachment(doc, text_attachment, "test", "text/plain") True >>> file = db.fetch_attachment(doc, 'test') >>> result = db.delete_attachment(doc, 'test') >>> result['ok'] True >>> db.fetch_attachment(doc, 'test') >>> del server['couchapp_test'] {u'ok': True} """ headers = {} if not content: content = "" content_length = 0 if name is None: if hasattr(content, "name"): name = content.name else: raise InvalidAttachment('You should provid a valid attachment name') name = resource.url_quote(name, safe="") if content_type is None: content_type = ';'.join(filter(None, mimetypes.guess_type(name))) if content_type: headers['Content-Type'] = content_type # add appropriate headers if content_length and content_length is not None: headers['Content-Length'] = content_length result = self.res(resource.escape_docid(doc['_id'])).put(name, payload=content, headers=headers, rev=doc['_rev']) if result['ok']: doc.update({ '_rev': result['rev']}) return result['ok']
def compact(self, dname=None, _raw_json=False): """ compact database @param dname: string, name of design doc. Usefull to compact a view. """ path = "/_compact" if dname is not None: path = "%s/%s" % (path, resource.escape_docid(dname)) res = self.res.post(path, _raw_json=_raw_json) return res
def doc_exist(self, docid): """Test if document exists in a database @param docid: str, document id @return: boolean, True if document exist """ try: data = self.res.head(resource.escape_docid(docid)) except ResourceNotFound: return False return True
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ name = resource.url_quote(name, safe="") res = self.res(resource.escape_docid(doc['_id'])).delete(name, rev=doc['_rev']) if res['ok']: doc.update({ '_rev': res['rev']}) return res['ok']
def delete_doc(self, doc, _raw_json=False): """ delete a document or a list of documents @param doc: str or dict, document id or full doc. @param _raw_json: return raw json instead deserializing it @return: dict like: .. code-block:: python {"ok":true,"rev":"2839830636"} """ result = { 'ok': False } if isinstance(doc, dict): if not '_id' or not '_rev' in doc: raise KeyError('_id and _rev are required to delete a doc') docid = resource.escape_docid(doc['_id']) result = self.res.delete(docid, _raw_json=_raw_json, rev=doc['_rev']) elif isinstance(doc, basestring): # we get a docid docid = resource.escape_docid(doc) data = self.res.head(docid) response = self.res.response result = self.res.delete(docid, raw_json=_raw_json, rev=response['etag'].strip('"')) return result
def fetch_attachment(self, id_or_doc, name, stream=False): """ get attachment in a document @param id_or_doc: str or dict, doc id or document dict @param name: name of attachment default: default result @param stream: boolean, response return a ResponseStream object @param stream_size: int, size in bytes of response stream block @return: str, attachment """ if isinstance(id_or_doc, basestring): docid = id_or_doc else: docid = id_or_doc['_id'] name = resource.url_quote(name, safe="") return self.res(resource.escape_docid(docid)).get(name, _stream=stream)
def save_doc(self, doc, encode_attachments=False, **params): """ Save a document. It will use the `_id` member of the document or request a new uuid from CouchDB. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses. (Idee from `Couchrest <http://github.com/jchris/couchrest/>`) @param doc: dict. doc is updated with doc '_id' and '_rev' properties returned by CouchDB server when you save. @param _raw_json: return raw json instead deserializing it @param params, list of optionnal params, like batch="ok" with `_raw_json=True` It return raw response. If False it update doc instance with new revision (if batch=False). """ if doc is None: doc = {} _raw_json = params.get('_raw_json', False) if '_attachments' in doc and encode_attachments: doc['_attachments'] = resource.encode_attachments(doc['_attachments']) if '_id' in doc: docid = resource.escape_docid(doc['_id']) res = self.res.put(docid, payload=doc, _raw_json=_raw_json, **params) else: try: doc['_id'] = self.server.next_uuid() res = self.res.put(doc['_id'], payload=doc, **params) except: res = self.res.post(payload=doc, **params) if _raw_json: return res if 'batch' in params and 'id' in res: doc.update({ '_id': res['id']}) else: doc.update({ '_id': res['id'], '_rev': res['rev']})
def get_doc(self, docid, wrapper=None, **params): """Get document from database Args: @param docid: str, document id to retrieve @param rev: if specified, allows you to retrieve a specific revision of document @param wrapper: callable. function that takes dict as a param. Used to wrap an object. @param _raw_json: return raw json instead deserializing it @return: dict, representation of CouchDB document as a dict. """ docid = resource.escape_docid(docid) doc = self.res.get(docid, **params) if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") return wrapper(doc) return doc
def doc_revisions(self, docid, with_doc=True, _raw_json=False): """ retrieve revisions of a doc @param docid: str, id of document @param with_doc: bool, if True return document dict with revisions as member, if false return only revisions @param _raw_json: return raw json instead deserializing it @return: dict: '_rev_infos' member if you have set with_doc to True : { "_revs_info": [ {"rev": "123456", "status": "disk"}, {"rev": "234567", "status": "missing"}, {"rev": "345678", "status": "deleted"}, ] } If False, return current revision of the document, but with an additional field, _revs, the value being a list of the available revision IDs. """ docid = resource.escape_docid(docid) try: if with_doc: doc_with_rev = self.res.get(docid, _raw_json=_raw_json, revs=True) else: doc_with_revs = self.res.get(docid, _raw_json=_raw_json, revs_info=True) except ResourceNotFound: if self.ui.verbose >=2: self.ui.logger.info("document %s not found" % docid) return None return doc_with_revs