我可以将Dictionary存储为对象的属性吗?

时间:2012-12-11 23:12:28

标签: python web-applications heroku sqlalchemy flask

使用Python / Flask / SQLAlchemy / Heroku。

想要将对象的字典存储为对象的属性:

要澄清

class SoccerPlayer(db.Model):
    name = db.Column(db.String(80))
    goals_scored = db.Column(db.Integer())

^我如何设置得分为一个字典的名称和目标?


更新:如果有任何不同,用户将输入名称和goals_scored。

此外,我正在网上搜索一个合适的答案,但作为一个菜鸟,我无法理解/实现我在Google上为我的Flask网络应用程序找到的内容。

3 个答案:

答案 0 :(得分:1)

django(比烧瓶更大的python web框架)默认情况下不支持此功能。但是在django你可以安装它,它被称为jsonfield(https://github.com/bradjasper/django-jsonfield)。

我想告诉你的是,并非所有数据库都知道如何存储二进制文件,但是他们知道如何存储字符串,而django的jsonfield实际上是一个包含字典的json转储的字符串。

因此,简而言之,你可以在烧瓶中做到

import simplejson

class SoccerPlayer(db.Model):
  _data = db.Column(db.String(1024))

  @property
  def data(self):
      return simplejson.loads(self._data)

  @data.setter
  def data(self, value):
      self._data = simplejson.dumps(value)

但要注意,这样你只能一次分配整个字典:

player = SoccerPlayer()
player.data = {'name': 'Popey'}
print player.data # Will work as expected
{'name': 'Popey'}
player.data['score'] = '3'
print player.data
# Will not show the score becuase the setter doesn't know how to input by key
{'name': 'Popey'} 

答案 1 :(得分:1)

如果您将此类信息存储在数据库中,我建议采用另一种方法:

class SoccerPlayer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    team_id = db.Column(db.Integer, db.ForeignKey('Team.id'))
    stats = db.relationship("Stats", uselist=False, backref="player")


class Team(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    players = db.relationship("SoccerPlayer")


class Stats(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    player_id = db.Column(db.Integer, db.ForeignKey('SoccerPlayer.id'))
    goals_scored = db.Column(db.Integer)
    assists = db.Column(db.Integer)
    # Add more stats as you see fit

使用此模型设置,您可以做到这样的疯狂事情:

from sqlalchemy.sql import func

max_goals_by_team = db.session.query(Team.id,
                    func.max(Stats.goals_scored).label("goals_scored")
                ). \
            join(SoccerPlayer, Stats). \
            group_by(Team.id).subquery()

players = SoccerPlayer.query(Team.name.label("Team Name"),
                                SoccerPlayer.name.label("Player Name"),
                                max_goals_by_team.c.goals_scored). \
                join(max_goals_by_team,
                        SoccerPlayer.team_id == max_goals_by_team.c.id,
                        SoccerPlayer.stats.goals_scored == max_goals_by_team.c.goals_scored). 
                join(Team)

因此,数据库做了艰苦的工作,拔出了每个团队最高目标的玩家,而不是在Python中完成所有这些。

答案 2 :(得分:1)

我会选择Sean提供的方法,然后你就可以了 规范化的数据库模式,可以更轻松地利用RDBMS为您完成艰苦的工作。如果, 但是,你坚持在你的数据库中使用类似字典的结构,我会 建议尝试hstore 数据类型,允许您将键/值对存储为单个值 Postgres的。我不确定Postgres默认是否创建hstore扩展名 Heroku提供的数据库,您可以通过在里面输入\dx命令来检查 psql。如果其中没有包含hstore的行,您可以按其创建 输入CREATE EXTENSION hstore;

由于SQLAlchemy中的hstore支持在0.8版本中可用,但不是 已发布(但希望将在未来几周内),您需要安装它 来自其Mercurial存储库:

pip install -e hg+https://bitbucket.org/sqlalchemy/sqlalchemy#egg=SQLAlchemy

然后像这样定义你的模型:

from sqlalchemy.dialects.postgresql import HSTORE
from sqlalchemy.ext.mutable import MutableDict

class SoccerPlayer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False, unique=True)
    stats = db.Column(MutableDict.as_mutable(HSTORE))

# Note that hstore only allows text for both keys and values (and None for
# values only).
p1 = SoccerPlayer(name='foo', stats={'goals_scored': '42'})
db.session.add(p1)
db.session.commit()

之后,您可以在查询中执行常规操作:

from sqlalchemy import func, cast

q = db.session.query(
    SoccerPlayer.name,
    func.max(cast(SoccerPlayer.stats['goals_scored'], db.Integer))
).group_by(SoccerPlayer.name).first()

结帐HSTORE docs 更多例子。