views:

30

answers:

1

My model:

class Order(models.Model):
    property_a = models.CharField()
    property_b = models.CharField()
    property_c = models.CharField()

Many users will access a given record in a short time frame via admin change page, so I am having concurrency issues:

User 1 and 2 open the change page at the same time. Assume all values are blank when they load the page. User 1 sets property_a to "a", and property_b to "b", then saves. A second later if user 2 changes property b and c then saves, it will quietly overwrite all the values from user 1. in this case, property_a will go back to being blank and b and c will be whatever user 2 put in.

I need recommendations on how to handle this. If I have to have a version field in the model, how do i pass it to the admin, where do I do the check so I can elegantly notify the user their changes can't be saved because another user has modified the record? Is there a more seamless way than just returning an error to the user?

A: 

The standard solution is to prevent your users from sharing a single record. It's not at all clear why so many users are messing with the exact same Order instance.

Consider that Order is probably a composite object and you've put too much into a single model. That's the first -- and best -- solution.

If (for inexplicable reasons) you won't decompose this, then you have to create a two-part update transaction.

  1. Requery the data. Compare with the original query as done for this user's session.

  2. If the data doesn't match the original query, then someone else changed it. The user's changes are invalidated, rolled back, wiped out, and the user sees a new query.

  3. If the data does match, you can try to commit the change.

The above algorithm has a race condition, which is usually resolved via low-level SQL. Note that it invalidates a user's work, making it maximally irritating.

That's why your first choice is to decompose your models to eliminate the concurrency.


my model has a miscellaneous notes field

This is a bad design. (a) Concurrency is ruined by collisions on this field. (b) There's no log or history of comments.

Item (b) means that a badly-behaved user can maliciously corrupt this data. If you keep notes and comments as a log, you can -- in principle -- limit users to changing only their own comments.

[In most databases with "miscellaneous notes" the field has become a costly, hard-to-maintain liability full of important but impossible-to-parse data. Miscellaneous notes is where users invent their own processes outside the application software. ]

"miscellaneous notes" must be treated like a log, with an unlimited number of notes -- date-stamped -- identified by user -- appended to the Order.

If you simply partition the design to put notes in a separate table, you solve your concurrency issues.

S.Lott
its a setting where an order is manipulated by more than one user within a short time frame. so sometimes their edit times overlap without them realizing. The order model's fields can't really be separated into other models (its all one-to-one info). If this is what you're referring to?
rsp
@rsp: "manipulated by more than one user" is incomprehensible to me. Seriously. I've only got 30 years of experience, and I've never seen anything like this. So I'm sure it's my limited experience that's getting in my way. Please UPDATE the question with some explanation for how this can happen and how these are not two separate rows of information with FK ties to a common `Order`.
S.Lott
I'm not sure if I came across as rude/inappropriate/unclear in my question/comment. If so, I apologize, I honestly did not mean to be. That being said, I do appreciate the advice/expertise since I am a novice but not the attitude. If you are still willing to help me:my model has a miscellaneous notes field. One order can be edited by multiple users on multiple computers within the course of about an hour. I could give them separate notes fields to avoid this concurrency issue but its truly miscellaneous info that I think belongs in one field. Please let me know if I did not explain well.
rsp
@rsp: (1) Add facts to the question, not comments on an answer. (2) Don't just repeat your question "manipulated by more than one user within a short time frame". Provide additional data, otherwise it must remaint "incomprehensible to me." I'm trying to elicit those facts. Call it "attitude" if that makes you happy, but provide the facts -- don't trivially repeat the incomprehensible part of your question.
S.Lott