I’ve been investigating the use of @transaction.atomic and with transaction.atomic() along with select_for_update() but neither seem to work as I expect (that’s not to say that they aren’t working though)
If I have a view that calls a form based on a single record, I would expect a lock to be placed on the database row to stop any other user making any change to that record, however I am able to edit the record in another browser session.
I’d be grateful for some guidance on how to implement record locks to stop updates from multiple form instances.
Here is my view:
@transaction.atomic
@api_view(['GET','POST'])
@permission_classes([IsAuthenticated])
def update_event(request, pk):
renderer_classes = [TemplateHTMLRenderer]
template = loader.get_template('ksail_events/event_update_form.html')
try:
myperms = EventUserPerms.objects.get(user = request.user, event = pk)
except:
myperms = EventUserPerms()
event_toupdate = get_object_or_404(Event.objects.select_for_update(), pk=pk)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = UpdateEventForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required
event_toupdate.start_date = form.cleaned_data['start_date']
event_toupdate.end_date = form.cleaned_data['end_date']
event_toupdate.venue = form.cleaned_data['venue']
event_toupdate.host = form.cleaned_data['host']
event_toupdate.theme = form.cleaned_data['theme']
event_toupdate.max_entries = form.cleaned_data['max_entries']
event_toupdate.blurb = form.cleaned_data['blurb']
event_toupdate.format = form.cleaned_data['format']
event_toupdate.event_image_url = form.cleaned_data['event_image_url']
event_toupdate.event_supporter_code = form.cleaned_data['event_supporter_code']
event_toupdate.theme_modifier = form.cleaned_data['theme_modifier']
event_toupdate.published = form.cleaned_data['published']
#ensure we have permissions to save the form
if (myperms.event_perm == 'WRITE' or request.user.is_staff or request.user.is_superuser):
event_toupdate.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('EventDetailsView', args=[pk]))
# If this is a GET (or any other method) create the default form.
else:
today_date = datetime.date.today().strftime("%Y-%m-%d")
start_date = event_toupdate.start_date.strftime("%Y-%m-%d")
end_date = event_toupdate.end_date.strftime("%Y-%m-%d")
form = UpdateEventForm(initial={'start_date': start_date, 'end_date': end_date, 'venue':event_toupdate.venue,
'host':event_toupdate.host, 'theme':event_toupdate.theme, 'max_entries':event_toupdate.max_entries,
'blurb':event_toupdate.blurb, 'format':event_toupdate.format, 'event_image_url':event_toupdate.event_image_url,
'event_supporter_code':event_toupdate.event_supporter_code, 'theme_modifier':event_toupdate.theme_modifier,
'published':event_toupdate.published})
context = {
'form': form,
'event_toupdate': event_toupdate,
'myevent':event_toupdate,
'myperms':myperms,
}
return HttpResponse(template.render(context, request))
Essentially I would like to lock the single record from the Event model that is used in this form such that it can be viewed by anyone but only updated by one person until the lock is released.
Currently the form can be opened by multiple people and the last one to hit submit wins.
Many thanks