A cautionary tale

Frank Millman frank at chagford.com
Thu Dec 5 03:57:28 EST 2013


"Steven D'Aprano" <steve at pearwood.info> wrote in message 
news:52a033f5$0$11112$c3e8da3 at news.astraweb.com...
> On Wed, 04 Dec 2013 11:16:40 +0200, Frank Millman wrote:
>
> [...]
>> Then I noticed that certain changes were not being written back to the
>> database. After some investigation, I found the error in a part of my
>> program that I have not had to look at for ages. When reading data in
>> from the database, I preserve a copy of the original value. When saving,
>> I compare that to the current value when deciding which columns need
>> updating. I do this in the obvious way -
>>
>>     on reading -
>>         orig_value = value
>
> As you know, that is not the obvious way to create a copy. That binds a
> new name to the same value. To create a copy, you need:
>
> orig_value = copy.copy(value)
>
> or for lists:
>
> orig_value = value[:]
>

True enough, but before I added my new data types, all the types I used were 
immutable, so I got away with it.

[...]

>
> I wouldn't do it that way. To my mind, the most obvious way of handling
> this is to add a "changed" flag to the object, and ensure that any
> modifications set the flag.
>
> Of course, that may end up being more work than the way you've done it,
> but it will save making potentially many copies of objects which don't
> need to be copied.
>
>

There are two (no, make that three) reasons why I need to preserve the 
original value -

1. A user can make changes to an object, and then before saving, select 
'cancel'. I then restore all values to their originals.

2.  I keep an 'audit trail' of changes to data rows, showing before and 
after values.

3. I use a form of 'optimistic concurrency control' to guard against two 
users updating the same row at the same time, resulting in one set of 
changes being overwritten. The classic form adds a 'timestamp' column to the 
table, which is timestamped on every update. Prior to executing an update, 
the timestamp is re-read from the database, and if not the same as the 
original, the update is aborted. My variation is to compare only those 
columns which have been changed, so I compare the re-read values with the 
orig_values. The benefit is that an organisation could have one user 
maintaining, say, credit information, while another may be trying to change 
the same person's telephone number. With my approach, both will succeed even 
if executed simultaneously [1].

Frank

[1] Not literally simultaneously. All that is required is that one user 
selects the row, and then before updating it, someone else selects the same 
row.






More information about the Python-list mailing list