Pregunta

Tengo una aplicación Django donde me permito al usuario importar un archivo CSV con los datos de contacto de miembros (#, nombre, apellido, etc.).

Cuando importar el archivo, la aplicación comprueba la base de datos para un registro coincidente y, o bien:. 1) inserta un nuevo registro si no existe ninguna coincidencia, o 2) actualiza los datos existentes con los nuevos datos

Mi pregunta es: ¿cuál es la mejor manera de implementar una función de deshacer, usando Django o Python recta, por lo que un usuario puede deshacer la operación de importación y volver múltiple registros de vuelta a sus estado original?

Mis pensamientos iniciales son para crear una tabla como ésta (pseudocódigo):

Table HISTORY
   unique_id
   record_affected_id
   old_value
   new_value

A continuación, si el usuario hace clic "deshacer" Me pueden buscar el id_exclusivo que está asociada con la transacción y establece todos los registros afectados por la transacción a la old_value.

Me pregunto si hay una manera más sencilla de hacer esto que me falta, o si alguien tiene experiencia con algo como esto.

¿Fue útil?

Solución

Tome un vistazo a django-reversion . Proporciona control de versiones para modelos de Django. Se pueden añadir fácilmente a proyecto existente.

No emplear el enfoque puntero "actual". En su lugar, se serializa objeto cada vez que se salvan, y lo almacena en un modelo independiente con Version genérico que señala clave externa a este objeto. (Campos de relación son serializados como claves primarias por defecto.) Además, permite a Versions grupo en Revisions de una manera flexible.

Por lo que puede hacer algo así:

  • Cuando usuario carga CSV, sólo tienes que guardar los cambios, como de costumbre, pero añadir decorador @revision.create_on_success a la función que realiza la importación, de modo que cualquier cambio en los registros realizados por la función que se almacenarán en una única revisión.
  • Cuando usuario selecciona "Deshacer", que acaba de revertir la última revisión.

Así es como se podría hacer ::

@revision.create_on_success
def import_csv(request, csv):
    # Old versions of all objects save()d here will
    # belong to single revision.

def undo_last_csv_import(request):
    # First, get latest revision saved by this user.
    # (Assuming you create revisions only when user imports a CSV
    # and do not version control other data.)
    revision = Revision.objects.filter(user=request.user)\
        .order_by('-date_created')[0]
    # And revert it, delete=True means we want to delete
    # any newly added records as well
    revision.revert(delete=True)

Se basa en el hecho de que se crea revisiones sólo cuando las importaciones de usuario CSV. Esto significa que si usted planea también de control de versiones de otros datos, entonces tendrá que implementar algún tipo de una bandera por la cual se puede obtener registros afectados por la última importación. Entonces se puede obtener un registro por esta bandera, conseguirlo última versión guardada, y revertir toda la revisión que pertenece a la versión. Como esto ::

def undo_last_csv_import(request):
    some_record = Record.objects.by_user(request.user).from_the_last_import()[0]
    latest_saved_version_of_some_record = Version.objects.get_for_date(
        some_record,
        datetime.now(), # The latest saved Version at the moment.
        )
    # Revert all versions that belong to the same revision
    # as the version we got above.
    latest_saved_version_of_some_record.revision.revert()

No es una solución hermosa, hay sin duda son maneras de hacerlo mejor con esta aplicación. Recomiendo tomar un vistazo al código para entender mejor cómo hace el trabajo muy bien documentado django-reversion, no pudo encontrar una función sin una cadena de documentación. ^ _ ^ D

(La documentación también es bueno, pero resultó ser un poco engañoso para mí, es decir, que escriben Version.objects.get_for_date(your_model, date), donde your_model es en realidad una instancia de modelo.)

Actualización: django-reversión se mantiene activa, por lo que no se basan en el código anterior mucho, y mejor comprobar su wiki sobre cómo gestionar versiones y revisiones de administración de Django fuera. Por ejemplo, los comentarios de revisión ya son compatibles, que pueden simplificar las cosas un poco.

Otros consejos

Es necesario tener el control de versiones, y la cuestión no es Python o Django, sino más bien cómo diseñar la base de datos para hacer esto. Una forma común es la de almacenar los documentos con identificadores únicos y no perder de vista que es el "actual". Deshacer es simplemente cuestión de poner la parte de atrás del puntero "actual" a una versión anterior. Esto es, por lo que yo puedo ver, lo que está haciendo.

A pesar de que esta es la forma común de hacerlo, no sé si es la mejor. Nunca he visto de otra manera, lo que podría significar que es la mejor, o que la mejor manera es no evidente. : -)

Hacer esto de una manera genérica en Django es probablemente un problema difícil, pero será más fácil si usted hace su soporte de aplicación Django de una manera personalizada.

Luego de entrar en la diversión (no) Problemas, como la forma de editar las cosas en un "futuro" revisión y publicar toda una serie de documentos a la vez, en una especie puesta en escena de forma del contenido. Pero es de esperar que no es necesario que. : -)

Su historial de apariencia fina de la tabla, excepto que no es necesario el campo nuevo_valor para llevar a cabo la acción de deshacer. Y sí, eso cómo se implementa a menudo 'deshacer' (la otra alternativa es el enfoque de poner un número de versión en todos los registros de Lennart). La ventaja de una mesa de diario aparte es que no es necesario tratar con el número de versión en consultas regulares.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top