如何使用字典为单个键赋予多个值?

时间:2013-11-09 07:41:51

标签: python dictionary cgi berkeley-db bsddb

我有一个html表单,其中包含FirstnameLastNameAgeGender以及ADD按钮。 我将数据输入表单并进入Berkeelys数据库。我的代码所做的是它只打印最后的值。我希望它应该显示与特定键相关的所有值

#!/usr/bin/python

import bsddb
import cgi

form = cgi.FieldStorage()

print "Content-type:text/html\n"
Fname = form.getvalue('firstname', '')
Lname = form.getvalue('lastname', '')
Age = form.getvalue('age', 0)
Gender = form.getvalue('gender', '')

#print Fname, Lname, Age 

db = bsddb.hashopen("/home/neeraj/public_html/database/mydb.db","w")
db['FirstName'] = Fname  
db['LastName'] = Lname
db['Age'] = Age 
db['Gender'] = Gender
db.close()
db = bsddb.hashopen("/home/neeraj/public_html/database/mydb.db","r")
#db = bsddb.hashopen("/home/neeraj/public_html/database/mydb.db")
print db['FirstName'], db['LastName'], db['Age'], db['Gender']
db.close()
print db 

5 个答案:

答案 0 :(得分:2)

您应该使用SQL数据库而不是基于dict的接口,因为SQL数据库已经在表中处理多个元组。

无论如何,如果你想拥有一个dict接口,你可以使用shelve模块(不推荐使用bsddb,所以你应该避免使用它)并将每个值保存在{{ 1}}:

list

以上代码输出:

import shelve

COLUMNS = ('FirstName', 'LastName', 'Age', 'Sex')

the_db = shelve.open('test.db', writeback=True)
for col_name in COLUMNS:
    if col_name not in the_db:
        the_db[col_name] = []

records = [
    ('John', 'Deer', 20, 'M'),
    ('Ada', 'Lovelace', 23, 'F'),
]

for record in records:
    for col_name, value in zip(COLUMNS, record):
        the_db[col_name].append(value)

the_db.close()

the_db = shelve.open('test.db')

for record in zip(*(the_db[col_name] for col_name in COLUMNS)):
    print(record)

the_db.close()

如果要使用SQL数据库,可以使用('John', 'Deer', 20, 'M') ('Ada', 'Lovelace', 23, 'F') 模块。 例如:

sqlite3

以上代码输出:

import sqlite3

conn = sqlite3.connect('test.sqlite')

cursor = conn.cursor()

cursor.execute('''
CREATE TABLE people (
    FirstName text,
    LastName text,
    Age int,
    Sex text
    )''')

cursor.execute('''
INSERT INTO people values ('John', 'Deer', 20, 'M')''')

cursor.execute('''
INSERT INTO people values ('Ada', 'Lovelace', 23, 'F')''')

conn.commit()

for record in cursor.execute('''SELECT * FROM people'''):
    print(record)

(注意(u'John', u'Deer', 20, u'M') (u'Ada', u'Lovelace', 23, u'F') 只是意味着字符串是unicode,它不会改变它们的值)

然而,这段代码存在一些问题(例如尝试运行两次......),但是如果你想要遵循这条路径,那么你必须首先学习SQL,所以继续进行并研究它(有很多在线教程。例如u'...'个。)

答案 1 :(得分:1)

将多个值关联到单个键的正确方法是使用例如“json.dumps”打包列表或字典值。

这是一个例子:

#!/usr/bin/python
from json import dumps
from json import loads
import bsddb

# write
users = bsddb.hashopen("users.db","w")
primarykey = 'amz'
users[primarykey] = dumps(dict(username="amz", age=30, bio="craftsman"))
users.close()

# read

users = bsddb.hashopen("users.db","r")

for key in users.keys():
    print loads(users[key])

users.close()

这是与bsddb一起使用的基本模式,适用于leveldb等其他键/值dbs。

<强>附加

鉴于bsddb hashmap键是按字典顺序排序的(即类似于python 2字符串),您可以使用具有可预测顺序的键构建哈希映射,从而省去了遍历所有表的麻烦。

要充分利用该功能,您必须构建有用的密钥。再次,您需要一个打包功能,将python排序顺序转换为lexigraphic顺序(即。11 > 2"11" < "2")。这是一个例子包装功能:

def pack(*values):
    def __pack(value):
        if type(value) is int:
            return '1' + struct.pack('>q', value)
        elif type(value) is str:
            return '2' + struct.pack('>q', len(value)) + value
        else:
            data = dumps(value, encoding='utf-8')
            return '3' + struct.pack('>q', len(data)) + data
    return ''.join(map(__pack, values))

这是一种天真的,你可以加倍努力并支持float并更好地打包int以节省空间。

例如,给定简化模式User(username, age),您可以构建另一个我们称为age_index的散列图,您可以使用该散列图轻松检索每个用户  30岁的hashmap如下所示:

   key    | value
 -----------------
  29  tom |   X
  30  amz |   X
  30  joe |   X
  30  moh |   X

这是一个人类可读的hasmap视图:该键实际上包含了上述pack函数。正如您所看到的,关键是age组合以及之前存储的项目的primarykey。在这种情况下,不使用该值,因为我们不需要它。请注意,每个键都必须是唯一的。

一旦该架构到位,您就可以使用Cursor.set_range(key)在bsddb中执行“选择查询”,称为范围查询。这会将光标设置在最近的键并返回关联的键/值对(语义可能会有所不同,具体取决于数据库)。

例如,要检索具有age=30的第一个人,请使用以下代码:

def get_first_person_with_age_thirty()
    key, _ = age_index.set_range(pack(30))  # we don't need value
    age, pk = unpack(key)
    # set_range, will set the key to "30" and a pk
    # or with a key prefix superior to 30.
    #  So we need to check that age is really 30.
    if age == 30:
        return loads(users[pk])

这将返回与用户amz关联的文档。

要进一步,需要使用其他bsddb接口,其入口点为bsddb.db.DBbsddb.db.DBEnvdocumentation]。使用此接口,您可以将多个hashmap绑定到相同的交易环境,即使不需要使用交易。

答案 2 :(得分:1)

您可以通过设置重复标记

,在伯克利数据库中针对单个键保存多个值
filename = '/path/to/berkeley/db/file'
fruitDB = db.DB()
fruitDB.set_flags(db.DB_DUP)
fruitDB.open(filename, None, db.DB_BTREE, db.DB_CREATE)
fruitDB.put(str(1), "Waqar")
fruitDB.put(str(1), "Umer")
fruitDB.put(str(2), "x")
fruitDB.put(str(2), "y")
fruitDB.put(str(4), "z")
fruitDB.put(str(5), "e")

但你无法使用&#39; Get&#39; BDB的方法你必须使用游标来检索项目,看看documentation为此,或者你可以使用

检索属于单个键的所有项目
cursor = fruitDB.cursor()
cursor.set(str(1))
record = cursor.current()
listTup = []
while record:
    print record
    listTup.append(record)
    record = cursor.next_dup()

输出

('1', 'Waqar')
('1', 'Umer')

这将返回元组列表,其中所有值都属于键&#39; 1&#39; 希望这会有所帮助。

答案 3 :(得分:0)

我想每次都使用w选项打开数据库,你每次都会覆盖它。只存储最后一个条目。您应该使用a

db = bsddb.hashopen("/home/neeraj/public_html/database/mydb.db","a")

摘自官方Python手册 - &gt;

    open() returns a file object, and is most commonly used with two arguments:
    open(filename, mode).
  
    
      

f = open('workfile','w')       第一个参数是包含文件名的字符串。第二个参数是另一个字符串,其中包含一些描述文件使用方式的字符。当只能读取文件时,模式可以是'r',仅写入的'w'(将删除具有相同名称的现有文件),'a'打开文件以进行追加;写入文件的任何数据都会自动添加到最后。

    
  

答案 4 :(得分:0)

正确的答案是:不要将BDB用于这种情况。对于简单的应用程序,您可以使用python 2.5中首次引入的内置sqlite模块。