Sale champs dans django
Dans mon application, j'ai besoin d'enregistrer les valeurs modifiées (ancien et nouveau) lorsque le modèle est enregistré. Les exemples ou code de travail?
J'en ai besoin pour premoderation de contenu. Par exemple, si l'utilisateur modifie quelque chose dans le modèle, puis administrateur peut voir toutes les modifications dans un tableau distinct et ensuite décider de les appliquer ou non.
- J'ai vu des questions similaires pour sale des champs, mais c'est le même problème; afin d'avoir un administrateur de regarder ce qui a changé, vous devez d'abord identifier ce qui a changé...
Vous devez vous connecter pour publier un commentaire.
Vous n'avez pas dit grand-chose sur votre cas d'utilisation spécifiques ou des besoins. En particulier, il serait utile de savoir ce que vous devez faire avec les informations de changement (combien de temps devez-vous conserver?). Si vous avez seulement besoin de les stocker pour une passagère fins, @S. Lott session solution peut-être mieux. Si vous voulez une piste de vérification complète de toutes les modifications apportées à vos objets stockés dans la base de données, essayez cette AuditTrail solution.
Mise à JOUR: L'AuditTrail code que j'ai lié ci-dessus est le plus proche que j'ai vu à une solution complète qui fonctionne pour votre cas, si elle a certaines limites (ne fonctionne pas du tout pour ManyToMany champs). Il permet de stocker toutes les versions précédentes de vos objets dans la base de données, de sorte que l'administrateur pourrait revenir à une version précédente. Vous devez travailler avec un peu si vous voulez que la modification ne prend effet qu'après approbation.
Vous pouvez aussi construire une solution personnalisée basée sur quelque chose comme @Armin Ronacher de DiffingMixin. Vous auriez stocker les diff dictionnaire (peut-être marinés?) dans un tableau pour l'admin pour la revoir plus tard et de les appliquer si vous le souhaitez (vous devez écrire le code pour prendre le diff et le dictionnaire de l'appliquer à un exemple).
J'ai trouvé Armin idée très utile. Voici mon variation;
Edit: j'ai testé ce BTW.
Désolé pour le long des lignes. La différence est (à part le nom) il ne caches locaux non-champs de relations. En d'autres termes, il ne met pas en cache un parent modèle de champs si présent.
Et il y a encore une chose; vous avez besoin de réinitialiser
_original_state
dict après l'enregistrement. Mais je ne voulais pas remplacersave()
méthode, car la plupart du temps, nous jeter instances de modèle après l'enregistrement.Django est actuellement l'envoi de toutes les colonnes de la base de données, même si vous avez simplement changé d'un. Pour changer cela, certains changements dans le système de base de données serait nécessaire. Cela pourrait être facilement mis en œuvre sur le code existant par l'ajout d'un ensemble de champs de données modifiées pour le modèle et l'ajout de noms de colonnes, chaque fois que vous
__set__
une valeur de colonne.Si vous avez besoin de cette fonctionnalité, je vous suggère de regarder l'ORM de Django, de l'appliquer et de mettre un patch dans le Django trac. Il devrait être très facile à ajouter que, et qu'il l'aidera d'autres utilisateurs. Lorsque vous faites cela, il faut ajouter un hook qui est appelée chaque fois qu'une colonne est définie.
Si vous ne voulez pas de hack sur Django lui-même, vous pouvez copier le dict sur la création de l'objet et de la diff d'elle.
Peut-être avec un mixin comme ceci:
Ce code n'est pas testé mais devrait fonctionner. Lorsque vous appelez
model.get_changed_columns()
vous obtenez un dict de toutes les valeurs modifiées. Bien sûr, cela ne fonctionnera pas pour mutable objets dans les colonnes parce que l'état initial est un plat copie de la dict.if value != self.__dict__.get(key, missing)
:__set__
approche? Il sonne comme il pourrait convenir à mes besoins, mais j'étais incapable de faire des progrès avec elle.J'ai étendu Trey Hunner de la solution à l'appui de m2m relations. J'espère que cela aidera d'autres personnes à la recherche d'une solution similaire.
On peut aussi vouloir fusionner les deux listes. Pour cela, remplacer la dernière ligne
avec
L'ajout d'une deuxième réponse, car beaucoup de choses ont changé depuis l'époque où cette question a été posté.
Il y a un certain nombre d'applications dans le Django monde que maintenant résoudre ce problème. Vous pouvez trouver plein liste de vérification des modèles et à l'histoire des applications sur le Django Paquets site.
J'ai écrit un post de blog la comparaison de quelques-unes de ces applications. Ce post est maintenant 4 ans et c'est un peu daté. Les différentes approches pour la résolution de ce problème semble être le même.
Les approches:
La django-retour paquet semble toujours être le plus populaire de la solution à ce problème. Il prend la première approche: sérialiser les changements au lieu de la mise en miroir de tables.
J'ai relancé django-simple-histoire quelques années en arrière. Il prend la deuxième approche: miroir chaque table.
Donc je vous conseille de l'aide d'une application pour résoudre ce problème. Il ya un couple de ceux populaire qui fonctionnent assez bien à ce moment.
Oh, et si vous êtes simplement à la recherche pour sale domaine de la vérification et de ne pas stocker l'historique des changements, découvrez FieldTracker de django-modèle-utils.
Continue sur Muhuk la suggestion de & ajout de Django reinhardt, les signaux et unique dispatch_uid vous pouvez réinitialiser l'état sur enregistrer sans écraser save():
Qui serait propre à l'état d'origine une fois sauvé sans avoir à remplacer save(). Le code fonctionne, mais pas sûr de ce que la perte de performance est de la connexion de signaux à __init__
J'ai étendu muhuk et smn de solutions pour inclure différence de vérification sur les clés primaires pour les clés étrangères et de l'un-à-un champs:
La seule différence est dans
_as_dict
j'ai changé la dernière ligne deà
Ce mixin, comme celles ci-dessus, peuvent être utilisés comme suit:
Si vous utilisez vos propres opérations (pas l'admin par défaut de l'application), vous pouvez économiser de l'avant et après les versions de votre objet. Vous pouvez enregistrer la version avant la session, ou vous pouvez le mettre dans "caché" des champs dans le formulaire. Les champs cachés de sécurité est un cauchemar. Par conséquent, l'utilisation de la session de conserver l'historique de ce qui se passe à cet utilisateur.
En outre, bien sûr, vous n'avez qu'à aller chercher l'objet précédent, de sorte que vous pouvez y apporter des modifications. Si vous avez plusieurs façons de contrôler les écarts.
Une mise à jour de solution m2m de soutien (à l'aide de mises à jour dirtyfields et de nouvelles _meta API et quelques corrections de bug), basé sur @Trey et @Tony ci-dessus. Ce qui a passé de base de la lumière de test pour moi.
pour tous renseignements, muhuk la solution ne peut pas, en vertu de python2.6 car il soulève une exception indiquant l'objet.__ init __()' accepte pas d'argument...
edit: ho! apparemment, il pourrait avoir été moi de détourner le le mixin... je n'ai pas fais attention et elle a déclaré que le dernier parent et ce parce que l'appel à init fini dans l'objet parent plutôt que l'autre parent qu'il noramlly serait avec diamant diagramme d'héritage! donc veuillez ne pas tenir compte de mon commentaire 🙂