標準のDjango=ユーザーモデルにリンクされているcreated_byフィールドを持つモデルがあります。モデルを保存するときに、現在のユーザーのIDを自動的に入力する必要があります。サイトのほとんどの部分ではビルトイン管理を使用しないため、管理レイヤーでこれを実行します。
管理者と他の場所の両方で機能するものが必要な場合は、カスタムモデルフォームを使用する必要があります。基本的な考え方は、__init__
メソッドをオーバーライドして追加のパラメーター(要求)を取得し、それをフォームの属性として保存し、saveメソッドをオーバーライドしてデータベースに保存する前にユーザーIDを設定することです。
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(MyModelForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(MyModelForm, self).save(*args, **kwargs)
if self.request:
obj.user = self.request.user
obj.save()
return obj
最も目立たない方法は、CurrentUserMiddleware
を使用して、スレッドローカルオブジェクトに現在のユーザーを格納することです。
from threading import local
_user = local()
class CurrentUserMiddleware(object):
def process_request(self, request):
_user.value = request.user
def get_current_user():
return _user.value
これで、このミドルウェアをMIDDLEWARE_CLASSESに追加するだけで済みます後認証ミドルウェア。
MIDDLEWARE_CLASSES = (
...
'Django.contrib.auth.middleware.AuthenticationMiddleware',
...
'current_user.CurrentUserMiddleware',
...
)
これで、モデルはget_current_user
関数を使用して、リクエストオブジェクトを渡さなくてもユーザーにアクセスできます。
from Django.db import models
from current_user import get_current_user
class MyModel(models.Model):
created_by = models.ForeignKey('auth.User', default=get_current_user)
Django CMSを使用している場合、独自のCurrentUserMiddlewareを定義する必要はありませんが、cms.middleware.user.CurrentUserMiddleware
およびcms.utils.permissions.get_current_user
関数を使用して現在のユーザーを取得できます。
ダニエルの答えは、リクエストオブジェクトを渡す必要があるため、管理者には直接働きません。これを行うには、get_form
メソッドをModelAdmin
クラスに追加しますが、フォームのカスタマイズから離れて、save_model
はModelAdmin
にあります。
def save_model(self, request, obj, form, change):
"""When creating a new object, set the creator field.
"""
if not change:
obj.creator = request.user
obj.save()
この全体的なアプローチは、私を悩ませました。一度だけ言いたいので、ミドルウェアで実装しました。認証ミドルウェアの後にWhodidMiddlewareを追加するだけです。
Created_byフィールドとmodified_byフィールドがeditable = False
に設定されている場合、フォームをまったく変更する必要はありません。
"""Add user created_by and modified_by foreign key refs to any model automatically.
Almost entirely taken from https://github.com/Atomidata/Django-audit-log/blob/master/audit_log/middleware.py"""
from Django.db.models import signals
from Django.utils.functional import curry
class WhodidMiddleware(object):
def process_request(self, request):
if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if hasattr(request, 'user') and request.user.is_authenticated():
user = request.user
else:
user = None
mark_whodid = curry(self.mark_whodid, user)
signals.pre_save.connect(mark_whodid, dispatch_uid = (self.__class__, request,), weak = False)
def process_response(self, request, response):
signals.pre_save.disconnect(dispatch_uid = (self.__class__, request,))
return response
def mark_whodid(self, user, sender, instance, **kwargs):
if 'created_by' in instance._meta.fields and not instance.created_by:
instance.created_by = user
if 'modified_by' in instance._meta.fields:
instance.modified_by = user
汎用ビューを使用して行う方法は次のとおりです。
class MyView(CreateView):
model = MyModel
def form_valid(self, form):
object = form.save(commit=False)
object.owner = self.request.user
object.save()
return super(MyView, self).form_valid(form)
クラスベースのビューを使用している場合、Danielの答えはもっと必要です。次を追加して、ModelFormオブジェクトでリクエストオブジェクトを使用できるようにします。
class BaseCreateView(CreateView):
def get_form_kwargs(self):
"""
Returns the keyword arguments for instanciating the form.
"""
kwargs = {'initial': self.get_initial()}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
'request': self.request})
return kwargs
また、すでに述べたように、ModelForm.save()の最後にobjを返す必要があります
bikeshedder の答えに基づいて、彼が実際に私のために働かなかったので、私は解決策を見つけました。
app/middleware/current_user.py
from threading import local
_user = local()
class CurrentUserMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
_user.value = request.user
return self.get_response(request)
def get_current_user():
return _user.value
settings.py
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',
'common.middleware.current_user.CurrentUserMiddleware',
]
model.py
from common.middleware import current_user
created_by = models.ForeignKey(User, blank=False, related_name='created_by', editable=False, default=current_user.get_current_user)
私はpython 3.5およびDjango 1.11.3を使用しています
次のようなものを使用することの問題は何ですか:
_class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = ['created_by']
def save(self, user):
obj = super().save(commit = False)
obj.created_by = user
obj.save()
return obj
_
viewsでmyform.save(request.user)
のように呼び出します。
ここに ModelFormの保存関数 があり、commit
パラメーターのみがあります。
ダニエルの答えが最高だとは思わない.
私が使用するコード:
from Django import forms
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(MyModelForm, self).__init__(*args, **kwargs)
def save(self, commit=True):
obj = super(MyModelForm, self).save(commit=False)
if obj.created_by_id is None:
obj.created_by = self.user
if commit:
obj.save()
return obj
Forms.ModelFormの「save」メソッドは、保存されたインスタンスを返します。
MyModelFormに最後の1行を追加する必要があります。
...
return obj
Create_objectまたはupdate_object汎用ビューを使用している場合、この変更が必要です。
保存されたオブジェクトを使用してリダイレクトを行います。
Django documentation Models and request.user :から
"CreateViewを使用してオブジェクトを作成したユーザーを追跡するには、カスタムModelFormを使用できます。ビューでは、編集するフィールドのリストに[ユーザーフィールド]を含めないでください。ユーザーを追加します。
from Django.contrib.auth.mixins import LoginRequiredMixin
from Django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(LoginRequiredMixin, CreateView):
model = Author
fields = ['name']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
将来の参考のために、この主題について見つけた最良の解決策:
https://pypi.python.org/pypi/Django-crum/0.6.1
このライブラリは、いくつかのミドルウェアで構成されています。このライブラリを設定した後、単純にモデルのsaveメソッドをオーバーライドし、次を実行します。
from crum import get_current_user
def save(self, *args, **kwargs):
user = get_current_user()
if not self.pk:
self.created_by = user
else:
self.changed_by = user
super(Foomodel, self).save(*args, **kwargs)
モデルを作成して抽象化し、すべてのモデルのモデルから継承すると、自動入力されたcreated_byおよびchanged_byフィールドが取得されます。