Skip to content

Commit ad54b75

Browse files
committed
Pass record to Model constructor
Previously we had no explicit Model constructor, and we were preparing the object by futzing with it in the delegating caster machinery. That allowed a user to implement their own constructor, though since it didn't receive any arguments it would have been of limited utility. Now a user can receive the raw query result in their Model subclass constructor (or __new__, which is actually what I want that's driving this).
1 parent 928708d commit ad54b75

File tree

3 files changed

+23
-18
lines changed

3 files changed

+23
-18
lines changed

postgres/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -782,11 +782,8 @@ def make(self, values):
782782
raise NotImplementedError
783783

784784
ModelSubclass = postgres.model_registry[self.name]
785-
786-
instance = ModelSubclass()
787-
instance._set_read_only_attributes(self.attnames)
788-
instance.set_attributes(**dict(zip(self.attnames, values)))
789-
785+
record = dict(zip(self.attnames, values))
786+
instance = ModelSubclass(record)
790787
return instance
791788

792789
return DelegatingCaster

postgres/orm.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,16 @@ def __str__(self):
202202
# =====
203203

204204
class Model(object):
205-
"""
205+
"""This is the base class for models in :py:mod:`postgres.orm`.
206+
207+
:param dict record: The raw query result
206208
207-
This is the base class for models in :py:mod:`postgres.orm`. Instances of
208-
subclasses of :py:class:`~postgres.orm.Model` will have an attribute for
209-
each field in the composite type for which the subclass is registered (for
210-
table and view types, these will be the columns of the table or view).
211-
These attributes are read-only. We don't update your database. You are
212-
expected to do that yourself in methods on your subclass. To keep instance
213-
attributes in sync after a database update, use the
209+
Instances of subclasses of :py:class:`~postgres.orm.Model` will have an
210+
attribute for each field in the composite type for which the subclass is
211+
registered (for table and view types, these will be the columns of the
212+
table or view). These attributes are read-only. We don't update your
213+
database. You are expected to do that yourself in methods on your subclass.
214+
To keep instance attributes in sync after a database update, use the
214215
:py:meth:`~postgres.orm.Model.set_attributes` helper.
215216
216217
"""
@@ -219,20 +220,18 @@ class Model(object):
219220
db = None # will be set to a Postgres object
220221
__read_only_attributes = [] # bootstrap
221222

222-
def __init__(self):
223+
def __init__(self, record):
223224
if self.db is None:
224225
raise NotBound(self)
225226
self.db.check_registration(self)
226-
self.__read_only_attributes = [] # overwrite class-level one
227+
self.__read_only_attributes = record.keys()
228+
self.set_attributes(**record)
227229

228230
def __setattr__(self, name, value):
229231
if name in self.__read_only_attributes:
230232
raise ReadOnly(name)
231233
return super(Model, self).__setattr__(name, value)
232234

233-
def _set_read_only_attributes(self, attribute_names):
234-
self.__read_only_attributes = attribute_names
235-
236235
def set_attributes(self, **kw):
237236
"""Set instance attributes, according to :py:attr:`kw`.
238237

tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ class MyModel(Model):
228228

229229
typname = "foo"
230230

231+
def __init__(self, record):
232+
from postgres.orm import Model
233+
Model.__init__(self, record)
234+
self.bar_from_init = record['bar']
235+
231236
def update_bar(self, bar):
232237
self.db.run( "UPDATE foo SET bar=%s WHERE bar=%s"
233238
, (bar, self.bar)
@@ -245,6 +250,10 @@ def test_orm_basically_works(self):
245250
one = self.db.one("SELECT foo.*::foo FROM foo WHERE bar='baz'")
246251
assert one.__class__ == self.MyModel
247252

253+
def test_orm_models_get_kwargs_to_init(self):
254+
one = self.db.one("SELECT foo.*::foo FROM foo WHERE bar='baz'")
255+
assert one.bar_from_init == 'baz'
256+
248257
def test_updating_attributes_works(self):
249258
one = self.db.one("SELECT foo.*::foo FROM foo WHERE bar='baz'")
250259
one.update_bar("blah")

0 commit comments

Comments
 (0)