web-dev-qa-db-ja.com

Djangoモデルに計算フィールドを追加する方法

Employeefirstname、およびlastnameフィールドを含む簡単なmiddlenameモデルがあります。

管理者側とおそらく他の場所で、私はそれを次のように表示したいと思います:

_lastname, firstname middlename
_

私にとってこれを行う論理的な場所は、計算フィールドを次のように作成することによるモデル内です。

_from Django.db import models
from Django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)
    name = ''.join(
        [lastname.value_to_string(),
        ',',
         firstname.value_to_string(),
        ' ',
         middlename.value_to_string()])

    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
        ]

admin.site.register(Employee, EmployeeAdmin)
_

最終的には、名前フィールドの値を文字列として取得する必要があると思います。私が得ているエラーはvalue_to_string() takes exactly 2 arguments (1 given)です。文字列への値には_self, obj_が必要です。 objの意味がわかりません。

これを行う簡単な方法がなければなりません、私はこれをしたい最初の人ではないと確信しています。

編集:これはダニエルの答えに修正された私のコードです。私が得るエラーは次のとおりです:

_Django.core.exceptions.ImproperlyConfigured: 
    EmployeeAdmin.list_display[1], 'name' is not a callable or an 
    attribute of 'EmployeeAdmin' of found in the model 'Employee'.


from Django.db import models
from Django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)

    @property
    def name(self):
        return ''.join(
            [self.lastname,' ,', self.firstname, ' ', self.middlename])

    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
]

admin.site.register(Employee, EmployeeAdmin)
_
44
cstrutton

わかりました...ダニエル・ローズマンの答えはうまくいくはずだったようです。いつものように、質問を投稿した後探しているものを見つけます

Django 1.5 docsで私はこの例を見つけました からすぐに動作しました。ご協力ありがとうございます。

動作したコードは次のとおりです。

from Django.db import models
from Django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)

    def _get_full_name(self):
        "Returns the person's full name."
        return '%s, %s %s' % (self.lastname, self.firstname, self.middlename)
    full_name = property(_get_full_name)


    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','full_name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
]

admin.site.register(Employee, EmployeeAdmin)
38
cstrutton

それはあなたがフィールドとしてすることではありません。その構文が機能していても、クラスにアクセスしたときではなく、クラスが定義されたときにのみ値を提供します。これをメソッドとして実行する必要があり、@propertyデコレータを使用して、通常の属性のように見せます。

@property
def name(self):
    return ''.join(
        [self.lastname,' ,', self.firstname, ' ', self.middlename])

self.lastnameなどは単なる値として表示されるため、他のメソッドを呼び出して変換する必要はありません。

64
Daniel Roseman

Daniel Rosemanのソリューションは、計算フィールドをModelの属性にしますが、それは QuerySetメソッドを介してアクセス可能にしません (例えば、。all().values())。これは、QuerySetメソッド データベースを直接呼び出す であり、Django Model

QuerySetsはデータベースに直接アクセスするため、解決策は、計算フィールドを追加してManager.get_queryset()メソッドをオーバーライドすることです。計算フィールドは、.annotate()を使用して作成されます。最後に、objectsModel Managerを新しいManagerに設定します。

これを示すコードを次に示します。

models.py

from Django.db.models.functions import Value, Concat
from Django.db import Model

class InvoiceManager(models.Manager):
    """QuerySet manager for Invoice class to add non-database fields.

    A @property in the model cannot be used because QuerySets (eg. return
    value from .all()) are directly tied to the database Fields -
    this does not include @property attributes."""

    def get_queryset(self):
        """Overrides the models.Manager method"""
        qs = super(InvoiceManager, self).get_queryset().annotate(link=Concat(Value("<a href='#'>"), 'id', Value('</a>')))
        return qs

class Invoice(models.Model):
    # fields

    # Overridden objects manager
    objects = InvoiceManager()

これで、.values()または.all()を呼び出して、linkで宣言された新しく計算されたManager属性にアクセスできるようになります。

.annotate()のようなF()その他の関数 を使用することも可能でした。

この属性はobject._meta.get_fields()でまだ利用できないと思います。ここに追加できると思いますが、どのように編集したかコメントがあると便利です。

20
Alex Petralia

私は最近、あなたが抱えている問題を非常に簡単に解決できるライブラリに取り組みました。

https://github.com/brechin/Django-computed-property

それをインストールし、INSTALLED_APPSに追加してから

class Employee(models.Model):
    ...
    name = computed_property.ComputedCharField(max_length=3 * 64, compute_from='full_name')

    @property
    def full_name(self):
        return '{LAST}, {FIRST} {MIDDLE}'.format(LAST=self.lastname, FIRST=self.firstname, MIDDLE=self.middlename')
6
brechin

この場合、管理サイトおよびそのような問題での表現にのみフィールドを使用する場合は、str()またはunicode()Django documentation here

class Employee(models.Model):
    # fields definitions
    def __str__(self):
        return self.lastname + ' ,' + self.firstname + ' ' + self.middlename
1
Farzad Vertigo