2013-07-16 43 views
24

Tôi có kiểu Employee đơn giản bao gồm các trường firstname, lastnamemiddlename.Cách thêm trường được tính toán vào kiểu Django

Về phía quản trị và khả năng ở những nơi khác, tôi muốn để hiển thị rằng:

lastname, firstname middlename 

Đối với tôi những nơi hợp lý để làm điều này là trong mô hình bằng cách tạo ra một lĩnh vực tính toán như vậy:

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) 

Cuối cùng những gì tôi nghĩ tôi cần là lấy giá trị của trường tên dưới dạng chuỗi. Lỗi tôi nhận được là value_to_string() takes exactly 2 arguments (1 given). Giá trị cho chuỗi muốn self, obj. Tôi không chắc chắn những gì obj có nghĩa là.

Phải có cách dễ dàng để thực hiện việc này, tôi chắc chắn tôi không phải là người đầu tiên muốn thực hiện việc này.

Chỉnh sửa: Đây là mã của tôi được sửa đổi thành câu trả lời của Daniel. Lỗi tôi nhận được là:

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) 
+1

thể trùng lặp của [Django mẫu: giá trị trường là tính fileds khác] (http://stackoverflow.com/questions/11465293/django-model-field-value-là-tính-of-khác-nộp) – Anto

Trả lời

28

Ok ... Câu trả lời của Daniel Roseman dường như đã hoạt động. Như mọi khi, bạn sẽ tìm thấy những gì bạn đang tìm kiếm sau khi bạn đăng câu hỏi.

Từ số django 1.5 docs I found this example hoạt động ngay lập tức. Cảm ơn tất cả sự giúp đỡ của bạn.

Đây là mã mà làm việc: giải pháp

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) 
44

Đó không phải là điều bạn làm như một trường. Ngay cả khi cú pháp đó hoạt động, nó sẽ chỉ đưa ra giá trị khi lớp được định nghĩa, không phải lúc bạn truy cập nó. Bạn nên làm điều này như một phương pháp, và bạn có thể sử dụng trang trí @property để làm cho nó trông giống như một thuộc tính bình thường.

self.lastname vv xuất hiện chỉ là giá trị của chúng, vì vậy không cần phải gọi bất kỳ phương pháp nào khác để chuyển đổi chúng.

+0

Tôi giả định này được đặt trong mô hình nhân viên ... mà đã cho tôi một lỗi. Phương pháp đó có nên vào lớp EmployeeAdmin không? – cstrutton

+0

Không, trong mô hình. Lỗi gì? –

+0

Đó là cách để làm điều đó. +1 – Matthias

6

Daniel Roseman của làm cho một lĩnh vực tính toán một thuộc tính của một Model, tuy nhiên nó does not make it accessible via QuerySet methods (ví dụ all(), .values()..). Điều này là do phương thức QuerySet call the database directly, phá vỡ django Model.

Vì QuerySets truy cập trực tiếp vào cơ sở dữ liệu, giải pháp là ghi đè phương thức .get_queryset() của Manager bằng cách thêm trường được tính toán của bạn. Trường được tính toán được tạo bằng cách sử dụng .annotate(). Cuối cùng, bạn đặt Trình quản lý objects trong số Model của mình thành Manager mới.

Dưới đây là một số mã chứng minh điều này:

mô hình.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() 

Bây giờ, bạn sẽ có thể gọi .values() hoặc .all() và truy cập các thuộc tính mới tính link như khai báo trong Manager.

Cũng có thể sử dụng other functions trong .annotate(), chẳng hạn như F().

Tôi tin rằng thuộc tính sẽ vẫn không có sẵn trong object._meta.get_fields(). Tôi tin rằng bạn có thể thêm nó ở đây, nhưng tôi chưa khám phá cách thức - mọi chỉnh sửa/nhận xét sẽ hữu ích.

+0

Chỉ vì sự hiểu biết của riêng tôi, tại sao không phải là def __str __ (tự): trả lại tự. Bất cứ điều gì là một giải pháp thích hợp cho vấn đề này? Điều này được đề cập trong các tài liệu ngay bên dưới phần OP được tham chiếu (phiên bản Django 1.10) https://docs.djangoproject.com/en/1.10/topics/db/models/#model-methods. Đây có phải là để bạn có thể có nhiều cách gọi hoặc đặt tên cho một đối tượng không? Ngoài ra, bạn có thể làm điều gì đó như def__str2__ trả lại self.othername? –

+0

@ MalikA.Rumi 'self.whatever' sẽ chỉ áp dụng cho một cá thể của mô hình, nhưng sẽ không áp dụng cho QuerySets (nghĩa là, tất cả các cá thể được trả về bởi' .all() 'hoặc' .filter() ') . 'self.whatever' chỉ một cá thể duy nhất và sẽ không tồn tại đối với QuerySets. –

+0

Cảm ơn Alex, điều này làm việc cho tôi với Django 1,11. Ngoài ra tôi cần sử dụng các trường được chú thích này trong Quản trị nhưng không thể, nhưng cách giải quyết [ở đây] (https://stackoverflow.com/a/26618982/503743) cho phép sử dụng điều này cũng với giao diện Quản trị. – Mrdev

1

Trong trường hợp này nếu bạn chỉ sẽ sử dụng lĩnh vực này cho đại diện trong site admin và các vấn đề như vậy, bạn có thể tốt hơn để xem xét trọng str() hoặc unicode() phương pháp của lớp như nó được đề cập trong tài liệu django here:

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

Gần đây tôi đã làm việc trên thư viện có thể giải quyết được vấn đề bạn gặp phải khá dễ dàng.

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

Install đó, thêm vào INSTALLED_APPS và sau đó

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') 
Các vấn đề liên quan