OK, so, we appear to have two camps:

1. People who think this should be handled by introducing one or more
   new methods to allow easy differentiation of the cases.

2. People who think this should be handled by adding new keyword
   arguments to save().

And, techncially, a third camp consisting of David, who thinks an
attribute on the model ought to control the behavior. But I'm going to
toss that out immediately because I don't want this to turn into
action-at-a-distance. Whatever mechanism we decide on should be
explicit and should be clearly visible from the point in the code
where you actually write data to the DB, which means one of the above
two mechanisms or a combination thereof.

Now, a couple of design goals for this API:

* The common case -- where you simply don't care and just want to save
  with no fuss -- needs to stay easy and so, in all likelihood, needs
  to be the default.

* The amount of new API to be introduced should be minimized, in order
  to maintain a simple interface.

* If there's anything we already have that can be leveraged to support
  this, we should do so.

So, the big trick is that people are approaching this from the
perspective of three-valued logic: either you force an INSERT or you
force an UPDATE or you don't care. To support this, we've had
proposals for two new methods (bringing the options up to three to
cover them all), two new keyword arguments (to cover the two
additional cases) or one new keyword argument with three possible
values (to cover all cases).

I think all of these are barking up the wrong tree, because this can
actually be accomplished by two minor tweaks.

The first is to look at the update() method that already exists on every
QuerySet and every default manager: this method *already* does one of
the things we want, namely force an UPDATE query to run. So, without
any changes whatsoever, a proposed API of, say::

    e = Employee(drone_id=1234567)
    e.salary = 1000000000
    e.save(force_update=True)

Can become::

    Employee.objects.filter(drone_id=1234567).update(salary=1000000000)

Now, the complaint people will have with this is that you can
accidentally leave off the filtering, or do it wrong, and make
everybody in the company a billionaire. Personally I think this is one
of those bits of SQL that people need to learn the hard way (and some
DBs have modes that won't let you run UPDATE or DELETE without a WHERE
clause), but as a concession I could see adding a tiny bit of new
behavior.

Currently, update() doesn't return anything; changing it to return the
number of rows affected would be a help. For bonus API-complication
points, it could sprout a kwarg that lets you assert a certain number
of affected rows, and then raise an exception and roll back the
transaction if that assertion fails.

That deals with one of the three cases (force UPDATE), which means
that save() itself only needs to deal with two cases: "force INSERT"
and "I don't care".

>From there, save() simply sprouts a "force_insert" kwarg, defaulting
to False, and you handle that when you care about it.

Also, the bikeshed should be blue.



-- 
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to