在Django Admin的更改页面中使用表显示模型字段

时间:2019-05-08 23:26:32

标签: python django-admin

问题:

  

我有一个项目模型,其内联模型可以说 InlineModel_1 InlineModel_2

     

我希望项目的“添加和更改”页面可以创建或编辑项目的字段和 InlineModel_1

     

此外,我还想要一个额外的更改页面,用于查看项目信息并编辑 InlineModel_2

1 个答案:

答案 0 :(得分:0)

  

Django 2.1.7和Python 3.7

我是Django的新手,所以请提供建议,如果有任何不正确之处,谢谢!

解决方案结果:

  1. 在变更列表页面

    将链接添加到原始更改页,并使用原始链接转到自定义的更改页

    enter image description here

  2. 原始更改页面,类似于添加页面

    enter image description here

  3. 新的自定义更改页面,用于内联添加

    enter image description here

过程

  1. 设置ProjectAdmin并将链接字段添加到原始更改页面
class ProjectAdmin(BaseAdmin):
    list_display = ('id', 'name', 'constructor', 'client',
                    'total_amount', 'edit_tag',
    readonly_fields = ('total_amount', 'order_form', 'project_info_table')
    # for add and edit use
    default_fields = (
        'name',
        'constructor',
        'client',
        'total_amount',
    )
    # for review and add inline use
    default_fieldset = (
        ('工程项目信息', {
            'fields': ('project_info_table',)
        }),
        ('报价单', {
            'classes': ('collapse',),
            'fields': ('order_form',),
        }),
    )

    # a link to orginal Change Page
    def edit_tag(self, obj):
        return mark_safe(
            f'<a href="{obj.get_absolute_url()}?edit=True">Edit</a>'
        )

    edit_tag.short_description = 'Edit'
  1. 向ModelAdmin添加方法以使用字段值生成表HTML
class Project(BaseModel):
     # ....
    # generate table1 html
     def project_info_table(self):
             # just one row, use thead only instead of a whole table
        table = """
           <table style="width:100%">
               <thead>
               <tr>
                   <th>Project name</th>
                   <th>Constructor</th>
                   <th>Client</th>
                   <th>Total amount</th>
               </tr>
               </thead>
               <tbody>
               <tr>
                   <td>{}</td>
                   <td>{}</td>
                   <td>{}</td>
                   <td>{}</td>
                </tr>
               </tbody>
           </table>
           """
        return format_html(
            table,
            self.name,
            self.constructor,
            self.client,
            self.total_amount()
        )

    project_info_table.short_description = '工程信息表'

    # generate table2 html
    def order_form(self):
        table = """
            <table style="width:100%">
                <thead>
                <tr>
                    <th>标号</th>
                    <th>类型</th>
                    <th>泵送</th>
                    <th>自卸</th>
                </tr>
                </thead>
                <tbody>{}{}</tbody>
            </table>
            """
        return format_html(
            table,

             # format_html_join can repeat the row with the values
             # from a iterator
            format_html_join(
                '\n', "<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
                ((
                    p.grade, p.type, p.pumpcrete, p.dumpcrete
                ) for p in self.products.all().order_by(
                    '-grade', 'type', 'pumpcrete'
                ))
            ),
            format_html("<tr><td>泵送方数低于:{}</td><td>加出泵费:{}</td><td>方数低于:{}</td><td>加空载费:{}</td></tr>",
                        self.min_cube_pump,
                        self.price_pump,
                        self.min_cube_extra,
                        self.price_extra
                        )
        )

    order_form.short_description = '合同报价单'    

    # another readonly field
    def total_amount(self):
        result = self.transaction_set.filter(
          is_deleted=False
        ).aggregate(
            Sum('total_price')
        )['total_price__sum'] or 0
        return '¥ {:,}'.format(result)
  1. 如果要保留原始的更改页面和上面的内联更改页面,请在管理员中覆盖change_view方法以显示
class ProjectAdmin(BaseAdmin):
     ....

    # different fields and inline according to GET method's parameter
    # need to reset fields and fieldset in different view

    def change_view(self, request, object_id, form_url='',
                    extra_context=None):
         if request.GET.get('edit', False):
            # Show original Change Page

             # Don't use fieldset cause it's only for customized page
            self.fieldsets = None
            self.fields = self.default_fields
            # able to user different inline for different page
            self.inlines = [DocumentInline]
        else:
            # Show customized page

            # don't sue fields use fieldset instead
            self.fields = None
            self.fieldsets = self.default_fieldset
            # use another inline for customized page
            self.inlines = [TransactionInline]
        return super().change_view(request, object_id,
                                   extra_context=extra_context)

     def add_view(self, request, form_url='', extra_context=None):
        self.fieldsets = None
        self.fields = self.default_fields
        self.inlines = [DocumentInline]
        return super(ProjectAdmin, self).add_view(request)