質問
私のアプリで保存変更値(新旧)がモデルが保存されます。例やコードについて教えてください。
このためpremoderationております。例えば、専用アプリをインストールなモデル、管理者が参照すべての変更が別表に決めることなどが明らかになった。
解決
いいものにご利用の場合。特に、蓄えればよいの変更情報(どのくらいいく必要があるのですか?).だく必要があるので過渡的@S.Lottのセッションの溶液であることができてしまいます。したい場合は完全監査証跡のすべての変更に格納されているオブジェクトをDBにみえてしまうこと AuditTrail液.
更新:のAuditTrailコードへの最寄り見てフル解決するためのケースでは、その一部の制限いかないんでManyToManyます。で商品を発送する場合は、以前のバージョンのオブジェクトDBので、管理者がロールバックのいず以前のバージョン。いすをご用意してお待ちしているビットをご希望の場合は変更しないまで承認されました。
きものをカスタムソリューションのような@んにちわ!RonacherのDiffingMixin.んのdiff辞書も漬け?) テーブルの管理者の審査後申請希望の場合(すなどを書く必要があり、コードのdiffの辞書を用いたインスタンス).
他のヒント
がその場で発音を確認することがんにちわ!の考えます。この変化
class DirtyFieldsMixin(object):
def __init__(self, *args, **kwargs):
super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
self._original_state = self._as_dict()
def _as_dict(self):
return dict([(f.name, getattr(self, f.name)) for f in self._meta.local_fields if not f.rel])
def get_dirty_fields(self):
new_state = self._as_dict()
return dict([(key, value) for key, value in self._original_state.iteritems() if value != new_state[key]])
編集:私はこの試験ちなみ.
申し訳なのです。その違いは外から名)のみのキャッシュ地元の非関す。つまらないキャッシュ親モデルの分野に存在する場合.
が一;必要なものをリセット _original_state
辞後ます。なる方法について、書かれてい save()
方法は、時代を捨てモデルインスタンス後ます。
def save(self, *args, **kwargs):
super(Klass, self).save(*args, **kwargs)
self._original_state = self._as_dict()
Djangoは現在送信のすべての列のデータベースの場合でも、変更しただけです。これを変更する変更をデータベースシステムが必要だと思います。これは簡単に既存のコードを追加するセットの汚れの分野では、モデルの追加カラム名です __set__
カラムの値です。
また、私はあなたのDjangoのORM、実施され、パッチ、Django trac.で非常に簡単に追加することは他のインターネットユーザーです。そうすると、追加フックと呼ばれる列を設定します。
ばんたいせDjangoそのもの、コピーして辞オブジェクトの創造とdiffます。
か、mixinのようになります:
class DiffingMixin(object):
def __init__(self, *args, **kwargs):
super(DiffingMixin, self).__init__(*args, **kwargs)
self._original_state = dict(self.__dict__)
def get_changed_columns(self):
missing = object()
result = {}
for key, value in self._original_state.iteritems():
if key != self.__dict__.get(key, missing):
result[key] = value
return result
class MyModel(DiffingMixin, models.Model):
pass
このコードは未審査が必要です。をご利用いただきます model.get_changed_columns()
する辞書内の全ての変数値です。このコースな作業のための可変オブジェクトにカラムがない状態からのフラットのコピーを辞書名またを設定した
私の延長配Hunnerソリューション支援m2m関係。この他の人のお役に立つことを探して同様の解決策です。
from django.db.models.signals import post_save
DirtyFieldsMixin(object):
def __init__(self, *args, **kwargs):
super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
post_save.connect(self._reset_state, sender=self.__class__,
dispatch_uid='%s._reset_state' % self.__class__.__name__)
self._reset_state()
def _as_dict(self):
fields = dict([
(f.attname, getattr(self, f.attname))
for f in self._meta.local_fields
])
m2m_fields = dict([
(f.attname, set([
obj.id for obj in getattr(self, f.attname).all()
]))
for f in self._meta.local_many_to_many
])
return fields, m2m_fields
def _reset_state(self, *args, **kwargs):
self._original_state, self._original_m2m_state = self._as_dict()
def get_dirty_fields(self):
new_state, new_m2m_state = self._as_dict()
changed_fields = dict([
(key, value)
for key, value in self._original_state.iteritems()
if value != new_state[key]
])
changed_m2m_fields = dict([
(key, value)
for key, value in self._original_m2m_state.iteritems()
if sorted(value) != sorted(new_m2m_state[key])
])
return changed_fields, changed_m2m_fields
ついにマネジメントの二つの分野のリストが表示されます。その最終ライン
return changed_fields, changed_m2m_fields
と
changed_fields.update(changed_m2m_fields)
return changed_fields
追加の第二回答のため く変更されたこの質問に掲載されたものを再録したもので.
多くのアプリは、Djangoの世界を解決するこの問題になっています。できる完全な リストのモデル監査-アプリの歴史 のDjangoパッケージサイトです。
書いた ブログ投稿 との比較このうち複数のアプリとなります。この投稿は現在、4歳でしょう。の異なるアプローチでこの問題を解決するに当たっても同じものです。
のアプローチ:
- 店内の全ての歴史的変化に直列化された形式(JSON?) 単一のテーブル
- 店内の全ての歴史的変遷をテーブルを反映し、これらのプログラム独自のモデル
- 店内の全ての歴史的変化を同一テーブルとしてのオリジナルモデル(ません)
の django-反転 パッケージもう一番人気リューションの問題です。で最初のアプローチ:serialize変化の代わりにミラーリングです。
私は復活 django-簡単な歴史 ができました。このアプローチ:ミラーをご用意しています。
くでおすすめ 使用アプリこの問題を解決する.あのカップルに人気な作品を望む声が多い。
Ohといった汚れの分野の確な保管すべての歴史的変遷、チェックアウト FieldTrackerからはdjango-モデル-utils.
引き続きMuhukの提案と付加Djangoの信号および独自のdispatch_uidきリセット状態を保存せずにオsave():
from django.db.models.signals import post_save
class DirtyFieldsMixin(object):
def __init__(self, *args, **kwargs):
super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
post_save.connect(self._reset_state, sender=self.__class__,
dispatch_uid='%s-DirtyFieldsMixin-sweeper' % self.__class__.__name__)
self._reset_state()
def _reset_state(self, *args, **kwargs):
self._original_state = self._as_dict()
def _as_dict(self):
return dict([(f.name, getattr(self, f.name)) for f in self._meta.local_fields if not f.rel])
def get_dirty_fields(self):
new_state = self._as_dict()
return dict([(key, value) for key, value in self._original_state.iteritems() if value != new_state[key]])
というクリーンの状態を一度に保存されずにオーバーライドます。このコードの作品がどのように性能があるの接続信号__init__
まmuhukと召ソリューションなどの差の確認に主キーのための外部キーと一対一の分野:
from django.db.models.signals import post_save
class DirtyFieldsMixin(object):
def __init__(self, *args, **kwargs):
super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
post_save.connect(self._reset_state, sender=self.__class__,
dispatch_uid='%s-DirtyFieldsMixin-sweeper' % self.__class__.__name__)
self._reset_state()
def _reset_state(self, *args, **kwargs):
self._original_state = self._as_dict()
def _as_dict(self):
return dict([(f.attname, getattr(self, f.attname)) for f in self._meta.local_fields])
def get_dirty_fields(self):
new_state = self._as_dict()
return dict([(key, value) for key, value in self._original_state.iteritems() if value != new_state[key]])
唯一の違いは _as_dict
変更しましたが、最終ラインから
return dict([
(f.name, getattr(self, f.name)) for f in self._meta.local_fields
if not f.rel
])
へ
return dict([
(f.attname, getattr(self, f.attname)) for f in self._meta.local_fields
])
このmixinのようなもの、使用できるように:
class MyModel(DirtyFieldsMixin, models.Model):
....
使用している場合は、ご自身の取引のデフォルトの管理、保存することができます前後のバージョンのオブジェクトです。保存することができます前のバージョンのセッションでは、やきもの"隠れた"分野の形式です。隠れた分野では、セキュリティ上の悪夢です。して使用することが求められますのセッションの保存歴史というこのユーザーです。
また、もちろん、だしを取り出す前のオブジェクトをすることができるのでもあります。いくつかの方法に違いがある。
def updateSomething( request, object_id ):
object= Model.objects.get( id=object_id )
if request.method == "GET":
request.session['before']= object
form= SomethingForm( instance=object )
else request.method == "POST"
form= SomethingForm( request.POST )
if form.is_valid():
# You have before in the session
# You have the old object
# You have after in the form.cleaned_data
# Log the changes
# Apply the changes to the object
object.save()
最新の液m2m支援(更新 dirtyfields -新 _meta API 一部のバグ修正)に基づき、@折や@トニー。このた基礎的な光を試験した。
from dirtyfields import DirtyFieldsMixin
class M2MDirtyFieldsMixin(DirtyFieldsMixin):
def __init__(self, *args, **kwargs):
super(M2MDirtyFieldsMixin, self).__init__(*args, **kwargs)
post_save.connect(
reset_state, sender=self.__class__,
dispatch_uid='{name}-DirtyFieldsMixin-sweeper'.format(
name=self.__class__.__name__))
reset_state(sender=self.__class__, instance=self)
def _as_dict_m2m(self):
if self.pk:
m2m_fields = dict([
(f.attname, set([
obj.id for obj in getattr(self, f.attname).all()
]))
for f,model in self._meta.get_m2m_with_model()
])
return m2m_fields
return {}
def get_dirty_fields(self, check_relationship=False):
changed_fields = super(M2MDirtyFieldsMixin, self).get_dirty_fields(check_relationship)
new_m2m_state = self._as_dict_m2m()
changed_m2m_fields = dict([
(key, value)
for key, value in self._original_m2m_state.iteritems()
if sorted(value) != sorted(new_m2m_state[key])
])
changed_fields.update(changed_m2m_fields)
return changed_fields
def reset_state(sender, instance, **kwargs):
# original state should hold all possible dirty fields to avoid
# getting a `KeyError` when checking if a field is dirty or not
instance._original_state = instance._as_dict(check_relationship=True)
instance._original_m2m_state = instance._as_dict_m2m()
皆様の情報muhukソリューションに失敗した下python2.6で例外が送旨'オブジェクトです。__ init__()'でない場合は引数...
編集:ho!どうやらかしになってしっ誤用は、mixin...私はビーチに位置注意"を宣言して最後の親会社およびそのために init 月のオブジェクトの親ではなく、次の親会社でnoramllyうダイヤモンドの図継承!なので無視してください私のコメント:)