2017-03-07 11 views
1

オブジェクト/インスタンスの履歴を記録するMixinを作成しようとしています。アイデアは十分に簡単なようだ:上書きmodels.Modelの、変更前のオブジェクトをつかむ変更を保存し、変更されたフィールドを参照し、別のテーブルへの変更を保存するために比較する方法を保存します。オブジェクト履歴のモデルミックスイン

class ObjectHistoryMixin(object): 

def save(self, *args, **kwargs): 
    previous_state = self.__class__.objects.get(pk=self.pk) 
    super(ObjectHistoryMixin, self).save(*args, **kwargs) 
    new_state = self 
    fields = self.__class__._meta.get_fields(include_parents=False) 
    for field in fields: 
     if getattr(previous_state, field.name) != getattr(new_state, field.name): 
      print('field {} changed'.format(field)) 

Iこのモデルでそれを試してみました:

class Insurer(ObjectHistoryMixin, models.Model): 

    created_date = models.DateTimeField(auto_now_add=True) 
    created_by = models.ForeignKey('users.User', on_delete=models.PROTECT) 

    name = models.CharField('naam', max_length=100) 

しかし、これは動作しません:

AttributeError at /portal/beheer/verzekeraars/9/bewerken/ 

'Insurer' object has no attribute 'submittedprescription' 

Request Method:  POST 
Request URL: http://127.0.0.1:8000/portal/beheer/verzekeraars/9/bewerken/ 
Django Version:  1.11b1 
Exception Type:  AttributeError 
Exception Value:  

'Insurer' object has no attribute 'submittedprescription' 

Exception Location:  C:/Users/Administrator/SVN/doras_val\portal\models.py in save, line 20 
Python Executable: C:\Users\Administrator\SVN\venvs\venv_doras_val\Scripts\python.exe 
Python Version:  3.6.0 
Python Path:  

['C:/Users/Administrator/SVN/doras_val', 
'C:\\Program Files (x86)\\JetBrains\\PyCharm 2016.3.2\\helpers\\pydev', 
'C:\\Users\\Administrator\\SVN\\doras_val', 
'C:\\Program Files (x86)\\JetBrains\\PyCharm 2016.3.2\\helpers\\pydev', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val\\Scripts\\python36.zip', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val\\DLLs', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val\\lib', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val\\Scripts', 
'c:\\python36-32\\Lib', 
'c:\\python36-32\\DLLs', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val', 
'C:\\Users\\Administrator\\SVN\\venvs\\venv_doras_val\\lib\\site-packages'] 

Server time: di, 7 Mrt 2017 13:15:38 +0100 
Environment: 


Request Method: POST 
Request URL: http://127.0.0.1:8000/portal/beheer/verzekeraars/9/bewerken/ 

Django Version: 1.11b1 
Python Version: 3.6.0 
Installed Applications: 
['django.contrib.admin', 
'django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.messages', 
'django.contrib.staticfiles', 
'django.contrib.humanize', 
'crispy_forms', 
'public', 
'users', 
'portal', 
'portal_patient', 
'portal_pharmacy', 
'portal_manager'] 
Installed Middleware: 
['django.middleware.security.SecurityMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.common.CommonMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware', 
'portal_patient.middleware.ActivePatientMiddleware', 
'portal_pharmacy.middleware.ActivePharmacyMiddleware'] 



Traceback: 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\core\handlers\exception.py" in inner 
    41.    response = get_response(request) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\core\handlers\base.py" in _get_response 
    187.     response = self.process_exception_by_middleware(e, request) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\core\handlers\base.py" in _get_response 
    185.     response = wrapped_callback(request, *callback_args, **callback_kwargs) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\views\generic\base.py" in view 
    68.    return self.dispatch(request, *args, **kwargs) 

File "C:/Users/Administrator/SVN/doras_val\portal_manager\mixins.py" in dispatch 
    11.   return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\views\generic\base.py" in dispatch 
    88.   return handler(request, *args, **kwargs) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\views\generic\edit.py" in post 
    240.   return super(BaseUpdateView, self).post(request, *args, **kwargs) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\views\generic\edit.py" in post 
    183.    return self.form_valid(form) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\contrib\messages\views.py" in form_valid 
    11.   response = super(SuccessMessageMixin, self).form_valid(form) 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\views\generic\edit.py" in form_valid 
    162.   self.object = form.save() 

File "C:\Users\Administrator\SVN\venvs\venv_doras_val\lib\site-packages\django\forms\models.py" in save 
    451.    self.instance.save() 

File "C:/Users/Administrator/SVN/doras_val\portal\models.py" in save 
    20.    print(getattr(previous_state, field.name)) 

Exception Type: AttributeError at /portal/beheer/verzekeraars/9/bewerken/ 
Exception Value: 'Insurer' object has no attribute 'submittedprescription' 

submittedprescription、この場合には、保険会社へのForeignKeyを持っています。私はこれを間違った方法で行っている可能性が非常に高いので、私に教えてください。

答えて

1

オブジェクトが実際にこのような関係を持たない場合、関連フィールドはインスタンス属性として設定できません。

フォールバック値を使用する方がよいでしょう。代替案として

if getattr(previous_state, field.name, None) != getattr(new_state, field.name, None): 

、あなたも、むしろ「1対多」の関係除外することもできます。:例えば

fields = self.__class__._meta.get_fields(include_parents=False) 
for field in fields: 
    if not field.one_to_many and getattr(previous_state, field.name) != getattr(new_state, field.name): 
     print('field {} changed'.format(field)) 

または非編集可能なフィールド除外:

fields = self.__class__._meta.get_fields(include_parents=False) 
for field in fields: 
    if field.editable and getattr(previous_state, field.name) != getattr(new_state, field.name): 
     print('field {} changed'.format(field)) 
+0

を私は 'request.user'に保存中にアクセスすることができないように見えます。これは一種のポイントなので、結局は別のルートを試す必要があるかもしれません...しかし、あなたの提案はすべてうまくいきます! –

+0

request.userのポイントは何ですか?それはあなたの質問にどのように関連していますか? –

+0

私は変更を行ったユーザーを追跡したいからです。しかし、私はそれが可能ではないと思うのは、保存は常に実際の要求から起動されるのではなく、例えばシェルがユーザーを持たないシェルだからです。 –