Hi Nick,

maybe this is a case for optimistic locking?
Does the thread at 
https://groups.google.com/d/msg/django-users/R7wJBTlC8ZM/MIzvYkWyCwAJ help?

Best regards,
Carsten


Am 27.12.21 um 06:36 schrieb Nick Farrell:
> Hi all.
> 
> I've been using Django for quite a number of years now, in various ways. Most 
> of the time, I find myself needing to create custom solutions to solve what 
> appears to be a very common problem. 
> 
> During the Christmas downtime, I decided to scratch this itch, and am putting 
> together what will hopefully turn into a solution to what I'll describe 
> below. I'm writing this here to get a sense of what the Django community sees 
> in this: is this a niche problem, is it shared by a few others, or is the 
> lack of these features a fundamental overnight in the core Django product?
> 
> *The problems *(from highest to lowest priority)*:*
> *
> *
> *1)* a form is rendered, the data is changed by a different task/request, 
> then the form is submitted, overwriting the recent changes.
> 
> Whenever models can be modified by multiple users (or even the same user in 
> different windows/tabs of their browser), this can happen. Also, if there are 
> any background processes which can modify the data (e.g. celery, or various 
> data synchronisation services), it's possible.
> In some situations this is no big deal, as the users do not really care, or 
> you know that the latest data would overwrite the previous data anyway. But 
> in general, this is a major risk, particularly when dealing with any health 
> or financial data. 
> 
> *2)* Not being able to safely lock a model/queryset beyond the lifetime of 
> the request.
> 
> This is related to problem 1, and solving problem 2 may in some circumstances 
> solve problem 1 - but not always. For example, depending on how the lock is 
> implemented, a "rogue" task/request may bypass the locking mechanism and 
> force a change to the underlying data. Also, if a lock is based on a session, 
> a user may have multiple tabs open in the same browser, using the same 
> session state (via shared cookies)
> 
> Solving this problem will reduce the chance that when a person does post a 
> form update, that there is any conflict, meaning fewer tears.
> 
> *3)* Not knowing that data has changed on the server until you submit a form.
> 
> Ideally there would be a means for someone viewing/editing a form to 
> immediately be notified if data changes on the server, obsoleting the current 
> form. This reduces the amount of wasted time is spent completing a form which 
> is already known to be out of sync, and will need to be redone anyway (as 
> long as problem 1 is solved; otherwise, there'll be data loss)
> 
> *4)* Smarter form validation
> 
> There are three types of missing validation: 
> - the first is that the default widgets do not support even very simple 
> client-side validation. For example, a text field might need to match a 
> regular expression. 
> - the second type is an ability to provide (in the model definition) 
> arbitrary javascript which can be executed client-side to provide richer 
> realtime validation during data entry.
> - the third type involves effectively providing provisional form data to the 
> server, and having Django validate() the form content without actually saving 
> the result. This would allow (for example) inter-field dependencies to be 
> evaluated without any custom code, providing near-realtime feedback to the 
> user that their form is invalid
> 
> 
> *The solutions*
> This is based on a day or so's experimentation, and I very much welcome any 
> feedback, both in terms of the usefulness of solving these problems in 
> general, as well as suggestion on better ways to solve the problems,  before 
> I go too far down any rabbit holes.
> 
> *Enhanced forms*
> - when rendering a form (using e.g. as_p()), alongside the normal INPUT DOM 
> elements, include additional hidden fields which store a copy of each form 
> field's initial value. 
> - when a form is submitted, compare these hidden values against the current 
> value in the database. If any of these do not match, the clean() method can 
> raise a ValidationError, allowing the user to know what has happened, and 
> that they will need to reload the form and try again, with the new stored 
> values.
> 
> This solution is minimally invasive. As well as modifying as_p() and friends, 
> a django template tag can also be exposed for those users who are rendering 
> their forms in a different way.
> Note that there is no reliance on additional attributed in the models: the 
> CAS-like checking performed is explicitly on the rendered form fields; it 
> does not matter if other model fields' values have changed, as someone 
> editing the form can neither see these field values, nor will their POSTing 
> modify these other fields' values.
> (I have implemented the above already, for generic model forms using a single 
> model)
> 
> *Locking*
> - provide a mixin which can be used on selected models. When used, a view 
> (usually some sort of form view) can attempt to lock() the model. If 
> successful (because it's not currently locked to someone else), only they can 
> perform writes to the model, until the lock expires. 
> - if the lock has expired, anyone (including the user who took out an expired 
> lock) may overate on the model instance.
> - the lock can be configured to either use the standard database ORM, or 
> redis. Redis will be more performant, but should not be a hard requirement
> - there will be pain points associated with using this without the websocket 
> solution, detailed below: there will not be a clean way to maintain the lock, 
> if the time between consecutive requests is greater than the timeout value
> 
> *Websocket*
> - provide a model mixin to enable websocket monitoring
> - use Django Channels to expose a websocket consumer
> - provide a templatetag which will include appropriate javascript into a web 
> page to initialise the client connection (if any forms are configured to be 
> monitored)
> - when the client initialises, it detects the form fields (as per the 
> 'Enhanced Forms' solution) and registers the model instance(s) with the 
> server, via the websocket.
> - whenever a monitored instance changes in Django, a signal is raised, 
> pushing notifications to any clients, along with the new values
> - the client can immediately compare the new instance values to the original 
> values on the form (stored in the hidden fields) and can update the widgets 
> directly if required (e.g. setting a CSS class to indicate the input is 
> invalid, and updating the validation message shown alongside that.
> 
> 
> A final aspect of the solution is the javascript widgets, but I feel my post 
> is already about 5 times too long.
> 
> Any thoughts/comments are welcome.
> 
> Thanks.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] 
> <mailto:[email protected]>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-users/e9d6ee80-19d2-4ca2-aa1b-10daf7217182n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/django-users/e9d6ee80-19d2-4ca2-aa1b-10daf7217182n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/1a689b41-e86c-9127-e579-022c48e53c21%40cafu.de.

Reply via email to