【问题标题】:Trying to serialize a queryset that uses select_related -- Can't obtain fields of foreignkey model尝试序列化使用 select_related 的查询集——无法获取外键模型的字段
【发布时间】:2016-04-12 12:52:37
【问题描述】:

当我执行查询时,我能够访问正确的字段('author.username')。

但如果我通过序列化程序运行相同的查询,它不会打印出 select_related 模型字段。

我应该指定所有字段,以及外键模型的附加字段吗??

views.py

query = Chat.objects.select_related('author').filter(id=chat.id)
print(query)    # [<Chat: 108>]
print(query[0]) # 108
print(query[0].author.username) # superman



context = serializers.serialize("json", Chat.objects.select_related('author').filter(id=chat.id))
print("---------")
print(context) # [{"model": "chats.chat", "pk": 108, "fields": {"author": 29, "text": "this is a message", "chatroom": 11, "written_at": "2016-01-07T23:03:28.968Z"}}]

--- 更新 --- 视图.py

context = ChatSerializer(chat)

# output
{u'text': u'come on', u'chatroom': OrderedDict([(u'id', 11), ('created_at', u'2016-01-07T00:27:28.391467Z'), ('creator', 29), ('participant', 1)]), u'written_at': u'2016-01-08T01:12:20.310776Z', u'author': OrderedDict([(u'id', 29), ('password', u'pbkdf2_sha256$24000$h0whlzx0BleT$4cUWdRkUsPYB7Ia6F+pYxX+31BMhJJfpWiLHfoL9NOY='), ('last_login', u'2016-01-07T00:26:37.907507Z'), ('email', u'superman@gmail.com'), ('username', u'superman'), ('first_name', u'clark'), ('last_name', u'kent'), ('is_active', True), ('is_admin', False), ('joined_on', u'2016-01-06T23:57:43.191484Z'), ('is_online', False), ('is_contractor', False), ('profile_pic', '/media/bicycle_z3NDBPI.jpeg'), ('braintree_id', u'20401140'), ('braintree_client_token', u'eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiI1MjIxM2UwZDQ4OGM0MmFkNTYzY2IzMDJlMDBkMmIyMWIwZWEzYzBiNWEzZTg2ZmNhMmJlNWM3MTI5YjNmNGJifGNyZWF0ZWRfYXQ9MjAxNi0wMS0wNlQyMzo1Nzo0NC42MTgzNzQ2NTgrMDAwMFx1MDAyNmN1c3RvbWVyX2lkPTIwNDAxMTQwXHUwMDI2bWVyY2hhbnRfaWQ9ZGZ6amRrdHM1ZnNxeXF0alx1MDAyNnB1YmxpY19rZXk9ZGtta245cDNjNTQzZGhudyIsImNvbmZpZ1VybCI6Imh0dHBzOi8vYXBpLnNhbmRib3guYnJhaW50cmVlZ2F0ZXdheS5jb206NDQzL21lcmNoYW50cy9kZnpqZGt0czVmc3F5cXRqL2NsaWVudF9hcGkvdjEvY29uZmlndXJhdGlvbiIsImNoYWxsZW5nZXMiOltdLCJlbnZpcm9ubWVudCI6InNhbmRib3giLCJjbGllbnRBcGlVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvZGZ6amRrdHM1ZnNxeXF0ai9jbGllbnRfYXBpIiwiYXNzZXRzVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhdXRoVXJsIjoiaHR0cHM6Ly9hdXRoLnZlbm1vLnNhbmRib3guYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhbmFseXRpY3MiOnsidXJsIjoiaHR0cHM6Ly9jbGllbnQtYW5hbHl0aWNzLnNhbmRib3guYnJhaW50cmVlZ2F0ZXdheS5jb20ifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6ZmFsc2UsInBheXBhbEVuYWJsZWQiOnRydWUsInBheXBhbCI6eyJkaXNwbGF5TmFtZSI6ImthbGxhcm9vIiwiY2xpZW50SWQiOm51bGwsInByaXZhY3lVcmwiOiJodHRwOi8vZXhhbXBsZS5jb20vcHAiLCJ1c2VyQWdyZWVtZW50VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3RvcyIsImJhc2VVcmwiOiJodHRwczovL2Fzc2V0cy5icmFpbnRyZWVnYXRld2F5LmNvbSIsImFzc2V0c1VybCI6Imh0dHBzOi8vY2hlY2tvdXQucGF5cGFsLmNvbSIsImRpcmVjdEJhc2VVcmwiOm51bGwsImFsbG93SHR0cCI6dHJ1ZSwiZW52aXJvbm1lbnROb05ldHdvcmsiOnRydWUsImVudmlyb25tZW50Ijoib2ZmbGluZSIsInVudmV0dGVkTWVyY2hhbnQiOmZhbHNlLCJicmFpbnRyZWVDbGllbnRJZCI6Im1hc3RlcmNsaWVudDMiLCJiaWxsaW5nQWdyZWVtZW50c0VuYWJsZWQiOnRydWUsIm1lcmNoYW50QWNjb3VudElkIjoia2FsbGFyb28iLCJjdXJyZW5jeUlzb0NvZGUiOiJVU0QifSwiY29pbmJhc2VFbmFibGVkIjpmYWxzZSwibWVyY2hhbnRJZCI6ImRmempka3RzNWZzcXlxdGoiLCJ2ZW5tbyI6Im9mZiJ9'), ('payment_method_nonce', u'dbd01080-35e2-4a3b-a695-560491a14567'), ('payment_method_token', u'cfty3w')])}

console.log() 输出

ChatSerializer(<Chat: 118>):
    author = NestedSerializer(read_only=True):
        id = IntegerField(label='ID', read_only=True)
        password = CharField(max_length=128)
        last_login = DateTimeField(allow_null=True, required=False)
        email = EmailField(max_length=255, validators=[<UniqueValidator(queryset=User.objects.all())>])
        username = CharField(max_length=80)
        first_name = CharField(max_length=45)
        last_name = CharField(max_length=45)
        is_active = BooleanField(required=False)
        is_admin = BooleanField(required=False)
        joined_on = DateTimeField(read_only=True)
        is_online = BooleanField(required=False)
        is_contractor = BooleanField(required=False)
        profile_pic = ImageField(allow_null=True, required=False)
        braintree_id = CharField(allow_blank=True, allow_null=True, max_length=255, required=False)
        braintree_client_token = CharField(allow_blank=True, allow_null=True, max_length=2000, required=False)
        payment_method_nonce = CharField(allow_blank=True, allow_null=True, max_length=255, required=False)
        payment_method_token = CharField(allow_blank=True, allow_null=True, max_length=255, required=False)
    text = CharField(max_length=255)
    chatroom = NestedSerializer(read_only=True):
        id = IntegerField(label='ID', read_only=True)
        created_at = DateTimeField(read_only=True)
        creator = PrimaryKeyRelatedField(queryset=User.objects.all())
        participant = PrimaryKeyRelatedField(queryset=Contractor.objects.all())
    written_at = DateTimeField(read_only=True)

【问题讨论】:

    标签: django django-queryset django-serializer django-select-related


    【解决方案1】:

    我猜你要搜索的是使用外键加入表

    请仔细阅读,内容虽长,但值得一读

    假设您有 2 个模型:- 员工和组织

    Organization(models.Model):
      organization_name = models.CharField()
    
    Employee(models.Model):
      employee_name = models.CharField()
      employee_organization= models.ForeignKey(Organzation,on_delete=models.CASCADE)
    

    您必须在前端访问员工模型,但您收到的数据是:

    data : { 
             employee_name:"some_employee_name",
             employee_organization:"some_org_id" #Here you are getting org_id but 
                                                 #that's not what you want I assume
           }
    

    但你真正想在前端得到的是:-

    data : {
            employee_name:"some_employee_name",
            employee_organization: {
                                  organization_name:"some_organization_name"
                                  }
           }
    

    这样您就可以访问“组织名称”而不是“组织 ID”。这称为使用外键连接表。

    为此,您必须为这样的模型创建序列化程序:-

     OrganizationSerializer(serializer.ModelSerializer):
        model = models.Organization
        field = "__all__"
    
     EmployeeSerializer(models.Model):
        employee_organization = OrganizationSerializer() # This does the trick
        model = models.Employee
        fields = "__all__"
    

    您应该像这样在视图中使用 EmployeeSerializer 通常将数据返回到前端:-

    class EmployeeView(APIView):
        def get(self, request, format=None):
            queryset= models.Employee.objects
                            .select_related("employee_organization")
                            .get(id="some_employee_id")
    
            serializer = serializers.EmployeeSerializer(queryset)
    
            return Response(serializer.data)
    

    现在您将获得所需的数据:-

     data : {
                employee_name:"some_employee_name",
                employee_organization: {
                                      organization_name:"some_organization_name"
                                     }
            }
    

    现在您可以随意提取“organization_name”。

    【讨论】:

      【解决方案2】:

      Django 的序列化程序不支持它:ticket。我建议你使用Django Rest Framework

      【讨论】:

      • 谢谢。我浏览了文档并创建了我的序列化程序。当我通过序列化程序将数据打印出来时,它看起来不错。但是,当我通过 redis.publish() 推送它时,它仅作为 django 模型字段出现 - 而不是实际的键:值。在顶部添加了输出。
      • 我实际上能够抓住它。我没有正确调用它。应该是 context.data
      猜你喜欢
      • 2018-11-17
      • 2021-12-23
      • 2016-04-17
      • 1970-01-01
      • 2012-09-24
      • 2017-04-22
      • 2011-05-08
      • 2022-11-13
      • 1970-01-01
      相关资源
      最近更新 更多