首页 > 解决方案 > djanga rest 框架:“str”对象没有属性“pk”

问题描述

我正在使用 Django 休息框架。我有一个现有的数据库(无法对其进行任何更改)。我的表 TestSuite 上有复合 pk。当我在 test_suites 上执行 get() 时,它会引发错误 - 'str' object has no attribute 'pk'。我没有在我的模型中定义 pk ,与 django 一样,我无法定义复合主键。因此,django 使用 'id' 一个自动生成的模型 pk。我无法在我的数据库中添加 id(因为我无法修改数据库)。post() 按预期工作,但是 get() 通过 postman() 以及可浏览的 API 引发错误。

我是 DRF 的新手。任何帮助表示赞赏。

数据库创建语句:

CREATE TABLE `test_suite` (
  `team_name` varchar(30) NOT NULL,
  `suite_name` varchar(100) NOT NULL,
  `description` varchar(200) DEFAULT NULL,
  `schedule` varchar(100) DEFAULT NULL,
  `email_list_ok` varchar(200) DEFAULT NULL,
  `email_list_fail` varchar(200) DEFAULT NULL,
  `template_name` varchar(100) NOT NULL,
  PRIMARY KEY (`team_name`,`suite_name`),
  KEY `fk_test_suite__email_templates` (`template_name`),
  CONSTRAINT `fk_test_suite__email_templates` FOREIGN KEY (`template_name`) REFERENCES `email_templates` (`template_name`),
  CONSTRAINT `fk_test_suite__team` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我需要对此表执行 get() 和 post() 。下面是我的模型、序列化程序和视图集。

模型.py

class Team(models.Model):
    team_name = models.CharField(primary_key=True, max_length=30)
    description = models.CharField(max_length=100, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'team'

class TestSuite(models.Model):
    team_name = models.ForeignKey(Team, on_delete=models.DO_NOTHING, db_column='team_name')
    suite_name = models.CharField(max_length=100)
    description = models.CharField(max_length=200, blank=True, null=True)
    schedule = models.CharField(max_length=100, blank=True, null=True)
    email_list_ok = models.CharField(max_length=200, blank=True, null=True)
    email_list_fail = models.CharField(max_length=200, blank=True, null=True)
    template_name = models.ForeignKey(EmailTemplates, on_delete=models.DO_NOTHING, db_column='template_name')

    class Meta:
        managed = False
        db_table = 'test_suite'
        unique_together = (('team_name', 'suite_name'),)

视图.py

class TestSuiteViewSet(viewsets.ModelViewSet):
    queryset = models.TestSuite.objects.values('team_name','suite_name', 'description','schedule','email_list_ok','email_list_fail','template_name')
    serializer_class = serializers.TestSuiteSerializer

class TeamViewSet(viewsets.ModelViewSet):
    queryset = models.Team.objects.all()
    serializer_class = serializers.TeamSerializer

序列化程序.py

class TestSuiteSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.TestSuite
        fields = ['team_name','suite_name', 'description','schedule','email_list_ok','email_list_fail','template_name']

错误回溯:

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/lib/python3.6/contextlib.py" in inner
  52.                 return func(*args, **kwds)

File "/usr/local/lib/python3.6/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/viewsets.py" in view
  116.             return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  495.             response = self.handle_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in handle_exception
  455.             self.raise_uncaught_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  492.             response = handler(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/mixins.py" in list
  48.         return Response(serializer.data)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in data
  768.         ret = super(ListSerializer, self).data

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in data
  262.                 self._data = self.to_representation(self.instance)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in to_representation
  686.             self.child.to_representation(item) for item in iterable

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in <listcomp>
  686.             self.child.to_representation(item) for item in iterable

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in to_representation
  530.                 ret[field.field_name] = field.to_representation(attribute)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/relations.py" in to_representation
  272.         return value.pk

Exception Type: AttributeError at /dqf_api/test_suites/
Exception Value: 'str' object has no attribute 'pk'

网址.py

router = routers.DefaultRouter()
router.register(r'teams', views.TeamViewSet)
router.register(r'test_suites', views.TestSuiteViewSet)
urlpatterns = [ url(r'^dqf_api/', include(router.urls))]

编辑:

我能够通过将以下代码添加到我的 serializers.py 来解决 get() 但是,现在我的 post() 不起作用 -ValueError at /dqf_api/test_suites/ Cannot assign "'ede'": "TestSuiteModel.team_name" must be a "Team" instance.

def to_representation(self, obj):
    return {
        'team_name': obj.get('team_name'),
        'suite_name': obj.get('suite_name'),
        'description': obj.get('description'),
        'schedule': obj.get('schedule'),
        'email_list_ok': obj.get('email_list_ok'),
        'email_list_fail': obj.get('email_list_fail'),
        'template_name': obj.get('template_name'),
    }
def to_internal_value(self, data):
        return {
            'team_name': data.get('team_name'),
            'suite_name': data.get('suite_name'),
            'description': data.get('description'),
            'schedule': data.get('schedule'),
            'email_list_ok': data.get('email_list_ok'),
            'email_list_fail': data.get('email_list_fail'),
            'template_name': data.get('template_name'),
        }

错误回溯:

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/lib/python3.6/contextlib.py" in inner
  52.                 return func(*args, **kwds)

File "/usr/local/lib/python3.6/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/viewsets.py" in view
  116.             return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  495.             response = self.handle_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in handle_exception
  455.             self.raise_uncaught_exception(exc)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/views.py" in dispatch
  492.             response = handler(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/mixins.py" in create
  21.         self.perform_create(serializer)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/mixins.py" in perform_create
  26.         serializer.save()

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in save
  214.             self.instance = self.create(validated_data)

File "/usr/local/lib/python3.6/dist-packages/rest_framework/serializers.py" in create
  943.             instance = ModelClass._default_manager.create(**validated_data)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/query.py" in create
  415.         obj = self.model(**kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/base.py" in __init__
  477.                     _setattr(self, field.name, rel_obj)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/fields/related_descriptors.py" in __set__
  197.                     self.field.remote_field.model._meta.object_name,

Exception Type: ValueError at /dqf_api/test_suites/
Exception Value: Cannot assign "'ede'": "TestSuiteModel.team_name" must be a "Team" instance.

标签: djangodjango-rest-frameworkattributeerror

解决方案


外键关系的序列化和反序列化存在问题。我通过将以下代码添加到 serializers.py 来修复它

class TestSuiteSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.TestSuiteModel
        fields = ['team_name','suite_name', 'description','schedule','email_list_ok','email_list_fail','template_name']

    def to_representation(self, obj):
        if isinstance(obj, dict): # get methods
            return obj
        else:
            self.fields['team_name'] = TeamSerializer()
            self.fields['template_name'] = EmailTemplatesSerializer()
            return super(TestSuiteSerializer, self).to_representation(obj)

推荐阅读