1

(編集:Djangoには「プロキシモデル」と呼ばれるまったく別の機能があることを知っています。フィールドをUserProfileに追加できる必要があるため、その機能は役に立ちません。)

だから私は新しいDjangoアプリを開始しています.django.contrib.auth.models.Userの拡張であるUserProfileモデルを作成しており、次のようにUserへの属性リクエストに失敗しました:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')

    def __getattr__(self, name, *args):
        if name == 'user' or name == '_user_cache':
            raise AttributeError(name)

        try:
            return getattr(self.user, name, *args)
        except AttributeError, e:
            raise AttributeError(name)

Userこれは通常は問題なく動作しますが、UserProfileAdmin.list_displayのフィールドを使用しようとすると壊れます。問題は、次の管理者検証コードにあります。

def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))

問題は、UserProfile のインスタンスにはメールなどのプロキシされたフィールドがありますが、UserProfile クラス自体にはありません。Django シェルでのデモ:

>>> hasattr(UserProfile, 'email')
False
>>> hasattr(UserProfile.objects.all()[0], 'email')
True

掘り下げた後、UserProfile._meta の django.db.models.options.Options.get_field をオーバーライドしたいようです。しかし、これを行うための非ハッキーな方法はないようです (私は現在、UserProfile._meta.[get_field, get_field_by_name] のモンキーパッチを含む非常にハッキーなソリューションを持っています)...何か提案はありますか? ありがとう。

4

3 に答える 3

2

複雑にしないでおく。以下は、使用するライブラリの UserProfile モデルの例です。

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    accountcode = models.PositiveIntegerField(null=True, blank=True)

それでおしまい。__getattr__オーバーライドを気にしないでください。代わりに管理インターフェースをカスタマイズします。

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

class UserProfileInline(admin.StackedInline):
    model = UserProfile

class StaffAdmin(UserAdmin):
    inlines = [UserProfileInline]
    # provide further customisations here

admin.site.register(User, StaffAdmin)

Userこれにより、インラインとして UserProfile にアクセスして、オブジェクトを CRUD できます。これで、UserProfile から User モデルに属性ルックアップをプロキシする必要がなくなりました。UserProfileのインスタンスからにアクセスするには、次User uを使用します。u.get_profile()

于 2011-03-06T05:45:58.100 に答える
0

これはプロキシ クラスではなく、関係です。元のモデルのサブクラスであるProxy Modelの詳細を参照してください。Meta.proxy = True

于 2011-03-06T02:03:19.983 に答える
0

User からのフィールドを UserProfileAdmin の list_display に表示したいだけの場合は、次を試してください。

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('user__email',)

フォームの一部として使用する場合は、追加フィールドとして UserProfileForm に追加し、フォームで検証します。

于 2011-03-06T05:14:15.400 に答える