¿Cómo manejo la concurrencia en un modelo de Django? No deseo que los cambios en el registro sean sobrescritos por otro usuario que lea el mismo registro.Control de concurrencia en Django modelo
Respuesta
La respuesta corta, esta realmente no es una pregunta de Django como se presentó.
El control de concurrencia a menudo se presenta como una pregunta técnica, pero en muchos aspectos es una cuestión de requisitos funcionales. ¿Cómo quiere/necesita su aplicación para trabajar? Hasta que sepamos eso, será difícil dar cualquier consejo específico de Django.
Pero, me siento como el senderismo, así que aquí va ...
Hay dos preguntas que tienden a preguntarme cuando se enfrentan a la necesidad de control de concurrencia:
- ¿Qué tan probable es que que dos usuarios necesitarán modificar al mismo tiempo el mismo registro?
- ¿Cuál es el impacto para el usuario si se pierden sus modificaciones a un registro?
Si la probabilidad de colisiones es relativamente alta, o si el impacto de perder una modificación es grave, entonces puede estar buscando algún tipo de bloqueo pesimista. En un esquema pesimista, cada usuario debe adquirir un bloqueo lógico antes de abrir el registro para su modificación.
El bloqueo pesimista tiene mucha complejidad. Debe sincronizar el acceso a los bloqueos, considerar la tolerancia a errores, la caducidad del bloqueo, los bloqueos de las las mayúsculas pueden ser anulados por los superusuarios, los usuarios pueden ver quién tiene el bloqueo, y así sucesivamente.
En Django, esto podría implementarse con un modelo de bloqueo separado o con algún tipo de clave foránea 'bloqueo de usuario' en el registro bloqueado. El uso de una tabla de bloqueo le da un poco más de flexibilidad en términos de almacenamiento cuando se adquirió la cerradura, usuario, notas, etc. Si necesita una tabla de bloqueo genérica que se puede usar para bloquear cualquier tipo de registro, eche un vistazo al django.contrib.contenttypes framework, pero rápidamente esto puede convertirse en el síndrome de abstracción del astronauta.
Si las colisiones son poco probables o se pierden, las modificaciones se vuelven a crear trivialmente, entonces se puede salir funcionalmente con técnicas de concurrencia optimistas. Esta técnica es simple y más fácil de implementar. Esencialmente, solo realiza un seguimiento de un número de versión o marca de tiempo de modificación y rechaza cualquier modificación que detecte como fuera de control.
Desde el punto de vista del diseño funcional, solo tiene que considerar cómo se presentan estos errores de modificación simultáneos a sus usuarios.
En términos de Django, control de concurrencia optimista se puede implementar reemplazando el método ahorrar en la clase del modelo ...
def save(self, *args, **kwargs):
if self.version != self.read_current_version():
raise ConcurrentModificationError('Ooops!!!!')
super(MyModel, self).save(*args, **kwargs)
Y, por supuesto, para cualquiera de estos mecanismos de concurrencia para ser robusto, que tiene que considerar transactional control. Ninguno de estos modelos es completamente viable si no puede garantizar las propiedades ACID de sus transacciones.
Ok, ese último ejemplo que escribiste era lo que yo quería saber, así que tengo que escribir el mío guardar el método para el modelo. Vengo de otro marco cuando se trata de establecer una propiedad para "comparar valores" con un control, por lo que no tenía idea de cómo implementarlo en Django, y no encontré ningún ejemplo en el tutorial inicial o me lo perdí. Pensé que dado que Django automatiza varias tareas que en otros marcos son hechas por el programador, esta tarea podría ser automatizada como en el marco en el que me referí primero – Pablo
Sí, mi opinión personal es que los marcos deberían evitar generalizar estos patrones de diseño debido a todas las funciones/implicaciones técnicas. YMMV ... –
Como se menciona a continuación, el código en el último fragmento está roto. Todavía puede aparecer una modificación entre el control de versión y el método de guardar. – julkiewicz
No creo que funcione un 'número de versión o marca de tiempo'.
Cuando self.version == self.read_current_version()
es , existe la posibilidad de que el número de versión haya sido modificado por otras sesiones justo antes de llamar al super().save()
.
Sin bloquear la tabla en cuestión, esto es correcto. Sin embargo, hay decoradores para simplificar el bloqueo de mesas con los modelos Django, que deberían evitar la condición de carrera a la que se refiere. – Cerin
Estoy de acuerdo con la explicación introductoria de Joe Holloway.
quiero contribuir con un fragmento de código de trabajo en relación a la última parte de su respuesta ("En términos de Django, control de concurrencia optimista se puede implementar reemplazando el método ahorrar en la clase del modelo ...")
usted puede utilizar las siguientes clases como un antepasado para su propio modelo
Si está dentro de una transacción db (ej. mediante el uso de transaction.atomic en un ámbito exterior) las siguientes afirmaciones son pitón seguro y consistente
En la práctica a través de una sola toma, las declaraciones filter + update proporcionan una especie de test_an d_set en el registro: verifican la versión y adquieren un bloqueo de nivel db implícito en la fila. Por lo tanto, el siguiente "guardar" puede actualizar los campos del registro para asegurarse de que es la única sesión que opera en esa instancia del modelo. La final cometer (por ejemplo ejecutado automáticamente por __exit__ en transaction.atomic) libera el bloqueo de nivel de db implícita en la fila
class ConcurrentModel(models.Model):
_change = models.IntegerField(default=0)
class Meta:
abstract = True
def save(self, *args, **kwargs):
cls = self.__class__
if self.pk:
rows = cls.objects.filter(
pk=self.pk, _change=self._change).update(
_change=self._change + 1)
if not rows:
raise ConcurrentModificationError(cls.__name__, self.pk)
self._change += 1
super(ConcurrentModel, self).save(*args, **kwargs)
- 1. Campo oculto en Django Modelo
- 2. ¿Cómo lograr operaciones atómicas (modelo de concurrencia) en JavaScript?
- 3. Concurrencia: atómico y volátil en C++ 11 modelo de memoria
- 4. ChoiceField en Django modelo
- 5. Modelo de concurrencia de Erlang vs Scala vs Go
- 6. Control de Django ModelForm salida
- 7. Reordenando campos en Django modelo
- 8. importación de modelo de Django
- 9. Modelo Django Encuesta
- 10. Modelo de usuario Django Oauth
- 11. Django modelo i18n de contenido
- 12. Columnas ordenando en el modelo de Django
- 13. Conéctese al modelo de usuario en Django
- 14. Usando self en Django Clases de modelo
- 15. Modelo múltipleAdmins/views para el mismo modelo en Django admin
- 16. campos del modelo dinámico Django
- 17. Django modelo. Objects.All() borrar() no
- 18. Django TimeField Modelo sin segundos
- 19. Django ahorrar modelo ForeignKey relación
- 20. Django admin, sección sin "modelo"?
- 21. Rs refs en concurrencia
- 22. Concurrencia en Amazon S3
- 23. concurrencia en PHP
- 24. Django modelo: eliminar() no provocó
- 25. ¿Cómo poner timedelta en el modelo django?
- 26. establecer db por modelo en django
- 27. Django ForeignKey _set en un modelo heredado
- 28. Atributo Django "last_login" en el modelo auth_user
- 29. Django filtra el modelo en ManyToMany count?
- 30. modelo django en create use __init__?
duplicado Posible de http: // stackoverflow .com/questions/320096/django-how-can-i-protect-against-concurrent-modification-of-database-entries – Tony