0

我有一个关于将代理模型与 Django Rest 框架和嵌套序列化一起使用的问题。

我的代理模型如下:

class MyField(Field):
    class Meta:
        proxy = True

    def field_type_name(self):
        # logic that computes the field type name here
        return "the result"

class MyForm(Form):
    class Meta:
        proxy = True

Field 模型是在我的项目中包含的另一个应用程序中定义的。我想在不修改模型的情况下添加自己的方法,所以我做了一个代理。

这些是代理模型的序列化程序:

class MyFieldSerializer(serializers.HyperlinkedModelSerializer):
    field_type = serializers.ChoiceField(source='field_type_name',
                                         choices=form_fields.NAMES)

    class Meta:
        model = MyField
        fields = ('url', 'field_type',)

class MyFormSerializer(serializers.HyperlinkedModelSerializer):
    fields = MyFieldSerializer(many=True)

    class Meta:
        model = MyForm
        fields = ('url', 'fields')

和视图集:

class MyFieldViewSet(viewsets.ModelViewSet):

    queryset = MyField.objects.all()
    serializer_class = MyFieldSerializer

class MyFormViewSet(viewsets.ModelViewSet):

    queryset = MyForm.objects.all()
    serializer_class = MyFormSerializer

网址.py:

router.register(r'fields', views.MyFieldViewSet)
router.register(r'forms', views.MyFormViewSet)

如果我去 /fields/ 它工作正常。我在代理模型中添加的方法执行正确。

[
    {
        "url": "http://127.0.0.1:8000/fields/1/", 
        "field_type": "the result", 
    }, 
    { ...

但是如果我去 /forms/ 我得到以下错误:

AttributeError at /forms/
'Field' object has no attribute 'field_type_name'

/Users/..../lib/python2.7/site-packages/rest_framework/fields.py in get_component
    """
    Given an object, and an attribute name,
    return that attribute on the object.
    """
    if isinstance(obj, dict):
        val = obj.get(attr_name)
    else:
        **val = getattr(obj, attr_name)**
    if is_simple_callable(val):
        return val()
    return val

▼ Local vars
Variable    Value
attr_name   u'field_type_name'
obj <Field: Cools2>

如您所见,obj 是 Field 而不是 MyField,这就是它无法调用 field_type_name 的原因。这只发生在嵌套序列化上。如果有人对我如何最好地解决这个问题有任何建议,我将不胜感激。

编辑:

根据 Kevin 的回复,我正在编辑代理模型以尝试解决此问题。

以下是供参考的基本模型:

class Form(AbstractForm):
    pass


class Field(AbstractField):
    form = models.ForeignKey("Form", related_name="fields")

这是我解决问题的尝试(使用Django 代理模型和 ForeignKey的示例):

class MyField(Field):
    class Meta:
        proxy = True

    def field_type_name(self):
        # logic that computes the field type name here
        return "the result"

    # this works
    @property
    def form(self):
        return MyForm.objects.get(id=self.form_id)


class MyForm(Form):
    class Meta:
        proxy = True

    # this does not work
    @property
    def fields(self):
        qs = super(MyForm, self).fields
        qs.model = MyField
        return qs

现在我可以从 MyField 获取 MyForm 但不能从 MyForm 获取 MyField (相反):

>>> MyField.objects.get(pk=1).form
<MyForm: Cool Form>

>>> MyForm.objects.get(pk=1).fields.all()
[]

一世

4

1 回答 1

0

这是因为您的模型Form(或MyForm)未配置为在您访问表单上的属性MyField时返回对象。field它未配置为替代您的代理版本。

自己试试,打开./manage.py shell并尝试阅读fields相关的管理器,它会返回一个Field对象的集合。

>>> form = MyForm.objects.all()[0].fields.all()

(顺便说一句,我必须猜测实际的模型结构,因为原始模型FieldForm模型未包含在您的示例中)。

如果它是一个只读字段,您可以使用serializers.SerializerMethodField向序列化程序添加一个方法(您的field_type_name(). 如果您希望能够编辑它,您最好编写自己的字段子类来处理转换。

于 2013-10-17T08:34:12.927 回答