【问题标题】:Django Admin Actions on single object单个对象上的 Django 管理操作
【发布时间】:2017-08-14 14:10:29
【问题描述】:

管理操作似乎适用于django 管理界面的列表视图中选择的几个项目:

就我而言,我希望在更改(一项)视图上有一个简单的操作按钮。

有没有办法让 django 管理操作在那里可用?

我知道我可以通过转到列表视图并在那里选择一项来解决这个问题。但是直接提供会更好。

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    在您的应用中为您的模型创建一个模板。

    templates/admin/<yourapp>/<yourmodel>/change_form.html
    

    使用此示例内容在更改现有对象时添加按钮。

    {% extends "admin/change_form.html" %}
    {% block submit_buttons_bottom %}
        {{ block.super }}
        {% if original %} {# Only show if changing #}
            <div class="submit-row">
                <a href="{% url 'custom-model-action' original.pk %}">
                     Another action
                </a>
            </div>
        {% endif %}
    {% endblock %}
    

    将该操作链接到任何 url 并重定向回您的模型更改对象视图。 More information about extending admin templates.

    更新:添加了对现有对象进行自定义操作的完整常见用例

    urls.py

    urlpatterns = [
        url(r'^custom_model_action/(?P<object_pk>\d+)/$',
            core_views.custom_model_action, name='custom-model-action')
    ]
    

    views.py

    from django.urls import reverse
    from django.contrib import messages
    from django.http import HttpResponse, HttpResponseRedirect
    
    def custom_model_action(request, object_pk):
        messages.info(request, 'Performed custom action!')
        return HttpResponseRedirect(
           reverse('admin:<yourapp>_<yourmodel>_change', args=[object_pk])
        )
    

    【讨论】:

    • 你错过了from django.urls import reverse
    【解决方案2】:

    与主题启动者询问的不同,但此 sn-p 允许从列表页面上以 最少代码量

    执行单个对象操作

    BaseAction 代码

    class AdminActionError(Exception):
        pass
    
    
    class AdminObjectAction:
        """Base class for Django Admin actions for single object"""
    
        short_description = None
        exp_obj_state = {}
    
        def __init__(self, modeladmin, request, queryset):
            self.admin = modeladmin
            self.request = request
            self.queryset = queryset
            self.__call__()
    
        def validate_qs(self):
            count = self.queryset.count()
            if count != 1:
                self.error("You must select one object for this action.")
    
            if self.exp_obj_state:
                if self.queryset.filter(**self.exp_obj_state).count() != 1:
                    self.error(f'Selected object does not meet the requirements: {self.exp_obj_state}')
    
        def error(self, msg):
            raise AdminActionError(msg)
    
        def get_object(self):
            return self.queryset.get()
    
        def process_object_action(self, obj):
            pass
    
        def validate_obj(self, obj):
            pass
    
        def __call__(self, *args, **kwargs):
            try:
                self.validate_qs()
                obj = self.get_object()
                self.validate_obj(obj)
            except AdminActionError as e:
                self.admin.message_user(self.request, f"Failed: {e}", level=messages.ERROR)
            else:
                with transaction.atomic():
                    result = self.process_object_action(obj)
    
                self.admin.message_user(self.request, f"Success: {self.short_description}, {result}")
    
    

    自定义操作[最少代码量]

    class RenewSubscriptionAction(AdminObjectAction):
        short_description = 'Renew subscription'
    
        exp_obj_state = {
            'child': None,
            'active_status': True,        
        }
    
        def process_object_action(self, obj):
            manager = RenewManager(user=obj.user, subscription=obj)
            return manager.process()
    
    

    AdminClass

    class SomeAdmin(admin.ModelAdmin):
        actions = [RenewSubscriptionAction]
    

    【讨论】:

      【解决方案3】:

      内置的管理操作对查询集进行操作。

      您可以使用 calable 来执行您想要的操作或显示其他内容:

      class ProductAdmin(admin.ModelAdmin):
          list_display ('name' )
          readonly_fields('detail_url)
      
      
      def detail_url(self, instance):
          url = reverse('product_detail', kwargs={'pk': instance.slug})
          response = format_html("""<a href="{0}">{0}</a>""", product_detail)
          return response
      

      或使用表格

      class ProductForm(forms.Form):
          name = forms.Charfield()
      
          def form_action(self, product, user):
              return Product.value(
                  id=product.pk,
                  user= user,
              .....
      
              )
      
      
      @admin.register(Product)
      class ProductAdmin(admin.ModelAdmin):
      
      # render buttons and links to
      def product_actions(self, obj):
              return format_html(
                  '<a class="button" href="{}">Action1</a>&nbsp;'
                  '<a class="button" href="{}">Action 2</a>',
                  reverse('admin:product-action-1', args=[obj.pk]),
                  reverse('admin:aproduct-action-3', args=[obj.pk]),
              )
      

      for more details about using forms

      【讨论】:

        【解决方案4】:

        如果你真的需要单个对象,我建议你使用这个解决方案,例如:

        class Gallery(TimeStampedModel):
            title = models.CharField(max_length=200)
            attachment = models.FileField(upload_to='gallery/attachment/%Y/%m/%d')
        
            def __str__(self):
                return self.title
        
            def process_button(self):
                return ('<button id="%(id)s class="btn btn-default process_btn" '
                        'data-value="%(value)s>Process</button>' % {'id': self.pk, 'value': self.attachment.url})
            process_button.short_description = 'Action'
            process_button.allow_tags = True
        

        在您的admin.py 中,将process_button 插入list_display

        class GalleryAdmin(admin.ModelAdmin):
            list_display = ['title', 'process_button', 'created']
            search_fields = ['title', 'pk']
            ....
        
            class Media:
                js = ('path/to/yourfile.js', )
        

        那么,在yourfile.js里面,你也可以处理它..

        $('.process_btn').click(function(){
            var id = $(this).attr('id');       // single object id
            var value = $(this).data('value'); // single object value
            ...
        });
        

        希望对您有所帮助..

        【讨论】:

          猜你喜欢
          • 2010-12-30
          • 2011-05-28
          • 2014-12-29
          • 2012-02-17
          • 2015-10-23
          • 2021-08-03
          • 1970-01-01
          • 2012-09-15
          • 1970-01-01
          相关资源
          最近更新 更多