I am using couchdb-python to access my CouchDB backend. Sometimes I want to know the URL that the library is accessing, in order to use curl or any other tool to access exactly the same URL. That is, I want to be able to copy/paste the encoded URL and perform a curl access, without manually editing anything.

Since couchdb-python is not giving me this information, I have built a small tool to get the URL:

import urllib

def get_couchdb_url(server, database, design_doc, view_name, **options):
    prefix = 'http://%s:%d' % (server, 5984)
    url = '/'.join([prefix, database, "_design", design_doc, '_view', view_name])
    params = urllib.urlencode(options)
    if params != "" : url += "?" + params
    return url

number='+666666666'
print get_couchdb_url('localhost', 'phonenumbers', 'control', 'allgeonums', key = number)

This gives me the following URL:

http://localhost:5984/phonenumbers/_design/control/_view/allgeonums?key=%2B666666666

Which, if I access with curl, gives:

curl -X GET 'http://localhost:5984/phonenumbers/_design/control/_view/allgeonums?key=%2B666666666'
{"error":"bad_request","reason":"invalid_json"}

If I manually edit, the URL, adding %22 before and after the key value, CouchDB accepts it and gives me the right answer:

curl -X GET 'http://localhost:5984/phonenumbers/_design/control/_view/allgeonums?key=%22%2B666666666%22'

Now I have two questions:

  • Can couchdb-python show me the URL it is accessing?
  • How can I tell urllib.urlencode to produce encoded data which can be accepted by CouchDB? According to the manual, the values must be url encoded. I am not sure how to do this, for the general case. I would like to avoid having to read the couchdb-python sources for just this simple problem.
有帮助吗?

解决方案

Sure it could and pretty simple, but using some internals:

import couchdb
from couchdb.http import urljoin
from couchdb.client import _encode_view_options
server = couchdb.Server()
db = server['blog']
res = db.view('posts/by_author', key='Mike', reduce=False, include_docs=True)
print urljoin(res.view.resource.url, **_encode_view_options(res.options))

Will give you output:

http://localhost:5984/blog/_design/posts/_view/by_author?key=%22Mike%22&reduce=false&include_docs=true

_encode_view_options the only need to enforce JSON value for key, startkey and endkey parameters and encode in same way any non string ones. You may just implement this function by yourself if import private functions is unavailable for some reasons.

其他提示

It seems the values in the query options must be first converted to json, and then they can be url-encoded. I have come up with the following code:

import simplejson as json
import urllib

def json_encode_options(**options):
    json_options = { }
    for k, v in options.iteritems():
        v_encoded = json.dumps(v)
        json_options[k] = v_encoded
    return urllib.urlencode(json_options)

def get_couchdb_url(server, database, design_doc, view_name, **options):
    prefix = 'http://%s:%d' % (server, 5984)
    url = '/'.join([prefix, database, "_design", design_doc, '_view', view_name])
    params = json_encode_options(**options)
    if params != "" : url += "?" + params
    return url

number='+666666666'
print get_couchdb_url('localhost', 'phonenumbers', 'control', 'allgeonums', key = number)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top