如何根据查询参数覆盖视图中只读字段的值?

时间:2017-12-27 20:41:27

标签: python django django-rest-framework

我的这个模型有一个只读字段,我在那里计算一些属性。

class BlastEvent(Event):
    tonnes = models.FloatField()
    blast_type = models.ForeignKey(BlastType)

    @property
    def size(self):
        return self.tonnes / BlastEvent.objects.all().aggregate(Max('tonnes'))['tonnes__max']

这是我的序列化器:

class BlastEventSerializer(serializers.HyperlinkedModelSerializer):

    size = serializers.ReadOnlyField()

    included_serializers = {'blast_type': BlastTypeSerializer}

    blast_type = ResourceRelatedField(
        queryset=BlastType.objects,
        related_link_view_name='blastevent-blasttype-list',
        related_link_url_kwarg='pk',
        self_link_view_name='blastevent-relationships'
    )

    class Meta:
        model = BlastEvent
        fields = ('url', 'id', 'tonnes', 'blast_type', 'size')

    class JSONAPIMeta:
        included_resources = ['blast_type']

这是我的观点:

class BlastEventViewSet(EventViewSet):
    queryset = BlastEvent.objects.all()
    serializer_class = BlastEventSerializer

现在我需要根据查询参数重新计算并覆盖此只读字段。我不确定哪个地方适合这样做。我尝试在我的视图的get_queryset()方法中这样做:

class BlastEventViewSet(EventViewSet):
    queryset = BlastEvent.objects.all()
    serializer_class = BlastEventSerializer

    def get_queryset(self):
        queryset = self.queryset
        instrument_id = self.request.GET.get('instrument_id')
        if instrument_id:
            for e in queryset:
                e.size = e.size + Instrument.objects.get(pk=instrument_id).distance
        return queryset

但它不起作用。它说'AttributeError:不能设置属性':

Traceback:  

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  86.             return self.dispatch(request, *args, **kwargs)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  489.             response = self.handle_exception(exc)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception
  449.             self.raise_uncaught_exception(exc)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  486.             response = handler(request, *args, **kwargs)

File "/home/nargiza/virtualenvs/myenv/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list
  40.         queryset = self.filter_queryset(self.get_queryset())

File "/home/nargiza/Development/geotechnical-data-platform-api/events/views.py" in get_queryset
  205.             e.size = ...

我可以根据查询参数覆盖此字段的值吗?

2 个答案:

答案 0 :(得分:0)

属性需要用于分配的setter。尝试将setter添加到BlastEvent,如下所示:

https://docs.python.org/3/library/functions.html#property

class BlastEvent(Event):
    tonnes = models.FloatField()
    blast_type = models.ForeignKey(BlastType)

    def _get_size(self):
        return self.tonnes / BlastEvent.objects.all().aggregate(Max('tonnes'))['tonnes__max']

    @property
    def size(self):
        if callable(self._get_size):
            return self._get_size()
        else:
            return self._get_size

    @size.setter
    def size(self, value):
        self._get_size = value

答案 1 :(得分:0)

我想出的解决方案是覆盖序列化器的to_representation()方法:

import {Component, OnInit} from '@angular/core';
import {DataServiceService} from './data-service.service';
import {ImpiantoModel} from './impianto.model';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';

systems: ImpiantoModel[];

constructor(private _dataService: DataServiceService) {}

getdata() {
   this._dataService.stream$().subscribe(
      result => this.systems = result
      );
}

 ngOnInit() {
    this._dataService.ngOnInit();
    this.getdata();
 }
}