基于动作表单在django admin中创建动态列

时间:2015-09-28 14:13:40

标签: django django-admin

我正在尝试在django admin上创建一个列,其值根据操作表单的输入而改变

所以例如

#Action form
class CalculateDistanceForm(ActionForm):        
    latitude = forms.DecimalField()
    longitude = forms.DecimalField(initial=0)

#Admin
@register(Distance)
class DistanceAdmin(admin.ModelAdmin):
    list_display = ['latitude','longitude','distance']
    action_form = CalculateDistanceForm
    actions = ['update distance']

    def distance(self,obj):
        # how do i get the request instance to determine the post parameters on the form
        return distance_calculator(obj.latitude,obj.longitude)

    def update_distance(self,request,queryset):
        lat = request.POST.get('latitude',None)
        lon = request.POST.get('longitude',None)
        queryset.calculate_price(lat,lon)

我的问题是如何动态显示查询集生成的新distance

2 个答案:

答案 0 :(得分:1)

正如我在其他答案中所说,在列方法中没有简单的方法来获取request。但即使它有可能,它也会与你的行动方法不同。

如果我们希望每次计算距离,我们可以将经度和经度保存在更永久的存储空间中。它可以是数据库,缓存或用户会话。保存到会话的示例:

@register(Distance)
class DistanceAdmin(admin.ModelAdmin):
    list_display = ['latitude','longitude'] # not displaying distance by default
    list_display_alt = ['latitude', 'longitude', 'distance'] # we will use that one if this was proper action call
    action_form = CalculateDistanceForm
    actions = ['update_distance']

    def changelist_view(self, request, *args, **kwargs):
        # We can't get user session in our column method, so we will copy our values from that session into `ModelAdmin` instance here:        

        if request.session.get('admin_latitude') and request.session.get('admin_longitude'):
            self.latitude = request.session['admin_latitude']
            self.longitude = request.session['admin_longitude']
        return super(DistanceAdmin, self).changelist_view(self, request, *args, **kwargs)


    def distance(self,obj):
        return distance_calculator(obj.latitude,obj.longitude, self.latitude, self.longitude)

    def get_list_display(self, request):
        if hasattr(self, 'latitude') and hasattr(self, 'longitude'): # that means it was our action call, so we will modify default columns
            return list_display_alt
        return super(DistanceAdmin, self).get_list_display(request)

    def update_distance(self,request,queryset):
        #self.latitude = request.POST.get('latitude',None)
        #self.longitude = request.POST.get('longitude',None)
        # it will better to use form here instead of raw POST processing

        form = CalculateDistanceForm(request.POST, request.FILES)
        form.fields['action'].choices = (('update_distance', "Update distance"), ) # this is necessary because default ActionForm has no idea about valid actions

        if form.is_valid():
            latitude = form.cleaned_data['latitude']
            longitude = form.cleaned_data['longitude']

            request.session['admin_latitude'] = latitude
            request.session['admin_longitude'] = longitude
        else:
            # if form wasn't valid, we can inform about that using messages framework here

答案 1 :(得分:0)

不幸的是,没有简单的解决方案可以通过distance方法获取您的请求。此外,该请求将与您的发布请求不同,因为django admin将在操作完成处理后执行自动重定向,但我们可以通过在您的操作中返回响应来阻止该请求。

当我们返回响应时,我们可以将纬度和经度保存到ModelAdmin实例中,稍后在distance方法中检索它。

@register(Distance)
class DistanceAdmin(admin.ModelAdmin):
    list_display = ['latitude','longitude'] # not displaying distance by default
    list_display_alt = ['latitude', 'longitude', 'distance'] # we will use that one if this was proper action call
    action_form = CalculateDistanceForm
    actions = ['update_distance']

    def distance(self,obj):
        return distance_calculator(obj.latitude,obj.longitude, self.latitude, self.longitude)

    def get_list_display(self, request):
        if hasattr(self, 'latitude') and hasattr(self, 'longitude'): # that means it was our action call, so we will modify default columns
            return list_display_alt
        return super(DistanceAdmin, self).get_list_display(request)

    def update_distance(self,request,queryset):
        #self.latitude = request.POST.get('latitude',None)
        #self.longitude = request.POST.get('longitude',None)
        # it will better to use form here instead of raw POST processing

        form = CalculateDistanceForm(request.POST, request.FILES)
        form.fields['action'].choices = (('update_distance', "Update distance"), ) # this is necessary because default ActionForm has no idea about valid actions

        if form.is_valid():
            self.latitude = form.cleaned_data['latitude']
            self.longitude = form.cleaned_data['longitude']

            request.method = GET  # tricking default changelist_view to think that there is no action called, without that we will end up in infinite loop.

            return self.changelist_view(request)
        else:
            # if form wasn't valid, we can inform about that using messages framework here
相关问题