@@ -28,7 +28,7 @@ def __get__(self, instance, owner):
28
28
owner ._check_abstract ()
29
29
q = sa .select ([owner .__table__ ])
30
30
if instance is not None :
31
- q = instance .append_where_primary_key ( q )
31
+ q = q . where ( instance .lookup () )
32
32
return q .execution_options (model = weakref .ref (owner ))
33
33
34
34
@@ -37,7 +37,7 @@ def __get__(self, instance, owner):
37
37
def select (* args ):
38
38
q = sa .select ([getattr (owner , x ) for x in args ])
39
39
if instance is not None :
40
- q = instance .append_where_primary_key ( q )
40
+ q = q . where ( instance .lookup () )
41
41
return q .execution_options (model = weakref .ref (owner ),
42
42
return_model = False )
43
43
return select
@@ -78,15 +78,18 @@ class UpdateRequest:
78
78
specific model instance and its database row.
79
79
80
80
"""
81
- def __init__ (self , instance ):
81
+ def __init__ (self , instance , lookup = True ):
82
82
self ._instance = instance
83
83
self ._values = {}
84
84
self ._props = {}
85
85
self ._literal = True
86
- if instance .__table__ is None :
87
- self ._pk_values = None
88
- else :
89
- self ._pk_values = _PrimaryKeyValues (instance )
86
+ self ._locator = None
87
+ if lookup and instance .__table__ is not None :
88
+ try :
89
+ self ._locator = instance .lookup ()
90
+ except LookupError :
91
+ # apply() will fail anyway, but still allow updates()
92
+ pass
90
93
91
94
def _set (self , key , value ):
92
95
self ._values [key ] = value
@@ -110,9 +113,9 @@ async def apply(self, bind=None, timeout=DEFAULT):
110
113
:return: ``self`` for chaining calls.
111
114
112
115
"""
113
- if self ._pk_values is None :
116
+ if self ._locator is None :
114
117
raise TypeError (
115
- 'GINO model {} is abstract, no table is defined ' .format (
118
+ 'Model {} has no table, primary key or custom lookup() ' .format (
116
119
self ._instance .__class__ .__name__ ))
117
120
cls = type (self ._instance )
118
121
values = self ._values .copy ()
@@ -146,8 +149,8 @@ async def apply(self, bind=None, timeout=DEFAULT):
146
149
opts = dict (return_model = False )
147
150
if timeout is not DEFAULT :
148
151
opts ['timeout' ] = timeout
149
- clause = self ._pk_values . append_where_primary_key (
150
- type ( self ._instance ). update
152
+ clause = type ( self ._instance ). update . where (
153
+ self ._locator ,
151
154
).values (
152
155
** values ,
153
156
).returning (
@@ -252,18 +255,6 @@ def _inspect_alias(target):
252
255
return sa .inspection .inspect (target .alias )
253
256
254
257
255
- class _PrimaryKeyValues :
256
- def __init__ (self , instance ):
257
- self ._values = {}
258
- for c in instance .__table__ .primary_key .columns :
259
- self ._values [c ] = getattr (instance , c .name )
260
-
261
- def append_where_primary_key (self , q ):
262
- for c , v in self ._values .items ():
263
- q = q .where (c == v )
264
- return q
265
-
266
-
267
258
class CRUDModel (Model ):
268
259
"""
269
260
The base class for models with CRUD support.
@@ -422,8 +413,7 @@ class CRUDModel(Model):
422
413
def __init__ (self , ** values ):
423
414
super ().__init__ ()
424
415
self .__profile__ = None
425
- # noinspection PyCallingNonCallable
426
- self .update (** values )
416
+ self ._update_request_cls (self , False ).update (** values )
427
417
428
418
@classmethod
429
419
def _init_table (cls , sub_cls ):
@@ -541,8 +531,34 @@ def append_where_primary_key(self, q):
541
531
542
532
await user.query.gino.first()
543
533
534
+ .. deprecated:: 0.7.6
535
+ Use :meth:`lookup` instead.
536
+
544
537
"""
545
- return _PrimaryKeyValues (self ).append_where_primary_key (q )
538
+ return q .where (self .lookup ()) # pragma: no cover
539
+
540
+ def lookup (self ):
541
+ """
542
+ Generate where-clause expression to locate this model instance.
543
+
544
+ By default this method uses current values of all primary keys, and you
545
+ can override it to behave differently. All instance-level CRUD
546
+ operations depend on this method internally.
547
+
548
+ :return:
549
+
550
+ .. versionadded:: 0.7.6
551
+
552
+ """
553
+ exps = []
554
+ for c in self .__table__ .primary_key .columns :
555
+ exps .append (c == getattr (self , c .name ))
556
+ if exps :
557
+ return sa .and_ (* exps )
558
+ else :
559
+ raise LookupError ('Instance-level CRUD operations not allowed on '
560
+ 'models without primary keys or lookup(), please'
561
+ ' use model-level CRUD operations instead.' )
546
562
547
563
def _update (self , ** values ):
548
564
return self ._update_request_cls (self ).update (** values )
@@ -551,7 +567,7 @@ async def _delete(self, bind=None, timeout=DEFAULT):
551
567
cls = type (self )
552
568
# noinspection PyUnresolvedReferences,PyProtectedMember
553
569
cls ._check_abstract ()
554
- clause = self . append_where_primary_key ( cls .delete )
570
+ clause = cls .delete . where ( self . lookup () )
555
571
if timeout is not DEFAULT :
556
572
clause = clause .execution_options (timeout = timeout )
557
573
if bind is None :
0 commit comments