誰がdjangoで組み込みアプリケーションを作成、更新、または作成したか

ご存じのように、djangoは非常に強力で柔軟なフレームワークです。 彼のために膨大な数のアプリケーションが作成され、個人用および公開用のアプリケーションも作成されました。 アプリケーションは、十分に単調で柔軟性があり、他のアプリケーションに組み込むこともできます。



挑戦する



誰がモデルのデータを作成および/または更新したかを追跡する必要があります。



アイデア



問題を解決して、ソリューションを任意のモデルに簡単に使用できるようにします。



解決策



モデル


どのモデルで将来の機能を使用するかわからないため、ミックスインを使用して追加するのが最善です。 Mixinは、メインクラスの追加機能を含むクラスです。 この場合、これらはcreated_by、updated_byフィールドになります。



from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ class CreatedByMixin(models.Model): created_by = models.ForeignKey(User, verbose_name=_('Created by'), related_name='%(class)s_created_items', ) class Meta: abstract=True class UpdatedByMixin(models.Model): updated_by = models.ForeignKey(User, verbose_name=_('Updated by'), related_name='%(class)s_updated_items', ) class Meta: abstract = True class CreatedUpdatedByMixin(CreatedByMixin, UpdatedByMixin): class Meta: abstract = True
      
      







すべてのケースに対して3つの異なるクラスを作成しました。作成者のみが重要な場合、更新者のみが重要な場合、作成者と更新者が重要な場合です。

モデルに作成者と更新者に関するデータがあるので、次のようにモデルを指定できます。







 from django.db import models from whovedonethis import models as who_models class TestCreatedUpdated(who_models.CreatedUpdatedByMixin): value = models.CharField('Value', max_length=255)
      
      







記録を保存する


モデルにはフィールドがありますが、そこに作成したユーザーを記録する方法は、レコードを更新しました。 これにはいくつかの解決策があります。







他の場合には何かが書き直されるか、解決策が普遍的でないため、最も普遍的な方法は信号を使用することであるように思えます。



Signalsは非常に強力なツールであり、djangoを使用してシステムの変更に対応できます(この場合、データベースのレコードを作成または更新します)。 しかし、それらを使用する場合、いくつかの問題があります。





誰がエントリを作成/更新したかを調べる方法は?




問題は、リクエストを送信したユーザーに関する情報が通常、リクエスト変数に格納されていることです。これは、 pre_saveシグナルの範囲内にありません。 この問題を解決するために、ユーザーに関する情報を保存するシングルトンクラスを使用します。 そして、ユーザーはミドルウェアを使用して示されます。



 class Singleton(type): ''' Singleton pattern requires for LoggedInUser class ''' def __init__(cls, name, bases, dicts): cls.instance = None def __call__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kwargs) return cls.instance class NotLoggedInUserException(Exception): ''' ''' def __init__(self, val='No users have been logged in'): self.val = val super(NotLoggedInUser, self).__init__() def __str__(self): return self.val class LoggedInUser(object): __metaclass__ = Singleton user = None def set_user(self, request): if request.user.is_authenticated(): self.user = request.user @property def current_user(self): ''' Return current user or raise Exception ''' if self.user is None: raise NotLoggedInUserException() return self.user @property def have_user(self): return not user is None from whovedonethis.loggedinuser import LoggedInUser class LoggedInUserMiddleware(object): ''' Insert this middleware after django.contrib.auth.middleware.AuthenticationMiddleware ''' def process_request(self, request): ''' Returned None for continue request ''' logged_in_user = LoggedInUser() logged_in_user.set_user(request) return None
      
      







信号を使用する方が便利なもの。


シグナルは関数なので、シグナルの動作を変更し、必要な機能を追加するデコレーターを作成してください。 この場合、これはユーザーを特定のフィールドに追加しています。 また、ユーザーを保存するフィールドにチェックを追加します。モデルで「created_by_field / updated_by_field」フィールドが指定されている場合は、それ以外の場合は標準フィールドの指定されたフィールドに保存します。 デコレーターは関数の動作のみを変更し、構造は変更しないため、functoolsのwraps関数を使用します。



 from functools import wraps from whovedonethis.loggedinuser import LoggedInUser def add_created_user(f): ''' Decorate pre_save signal for adding created user ''' @wraps(f) def wrapper(sender, instance, **kwargs): if not instance.id: created_by_attr = getattr(instance, "created_by_field", "created_by" ) setattr(instance, created_by_attr, LoggedInUser().current_user) return f(sender, instance, **kwargs) return wrapper def add_updated_user(f): ''' Decorate pre_save signal for adding created user ''' @wraps(f) def wrapper(sender, instance, **kwargs): updated_by_attr = getattr(instance, "updated_by_field", "updated_by" ) setattr(instance, updated_by_attr, LoggedInUser().current_user) return f(sender, instance, **kwargs) return wrapper add_created_and_updated_user = lambda x: add_created_user(add_updated_user(x)) add_created_and_updated_user.__doc__ =\ ''' Decorate pre_save signal for adding created and updated user '''
      
      







まとめ



まあ、それは基本的にそれです。 今では、すべてをまとめて組み込みアプリケーションを作成します。



リポジトリ:




PS


特にスペルと句読点についてのコメントとエラー表示をありがとう。



この記事の執筆は、PyCon 2011とのCorey Oordtトークに触発されました。



UPD。

デコレータで信号を使用する例:


 from django.db.models.signals import pre_save from django.dispatch import receiver from whovedonethis import decorator from testlib.models import TestCreated @receiver(pre_save, sender=TestCreated) @decorator.add_created_user def pre_save_testcreated_handler(sender, instance, **kwargs): pass
      
      






All Articles