将有效负载预处理到 Django 中的惯用方法是什么?

What's the idiomatic way to pre-process a payload into Django?

我正在尝试 post 将 Jira webhook 连接到我使用 REST 框架在 Django 中设置的特定模型。这是模型的代码:

class Webhook(models.Model):
    '''issue object with jia metadata'''
    event = models.CharField(max_length=256)
    hook_id = models.IntegerField(max_length=10)
    self = models.CharField(max_length=1024)
    issue_key = models.CharField(max_length=12)
    fields_summary = models.CharField(max_length=1024)
    user_id = models.CharField(max_length=256)
    issue_summary = models.CharField(max_length=1024)
    issuetype_self = models.CharField(max_length=1024)
    issuetype_id = models.IntegerField(max_length=6)
    issuetype_name = models.CharField(max_length=48)
    reporter = models.CharField(max_length=256)
    updated = models.DateTimeField()
    created = models.DateTimeField()
    description = models.CharField(max_length=1024)
    status_description = models.CharField(max_length=48)
    status_name = models.CharField(max_length=48)
    statuscategory_name = models.CharField(max_length=48)
    project_name = models.CharField(max_length=16)
    creator = models.CharField(max_length=256)
    attachment = models.CharField(max_length=1024, blank=True, null=True)
    thumb = models.CharField(max_length=1024, blank=True, null=True)

下面是将 POSTed 到 Django 应用程序中的 webhook 代码。

{
    "webhookEvent": "jira:issue_updated",
    "user": {
        "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
        "name": "foo",
        "emailAddress": "foo@rando_company.com",
        "avatarUrls": {
            "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
            "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
            "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
            "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
        },
        "displayName": "foo",
        "active": true
    },
    "issue": {
        "id": "33062",
        "self": "https://my.jira-instance.com/rest/api/2/issue/33062",
        "key": "jira-project-key-355",
        "fields": {
            "summary": "The week ahead",
            "progress": {
                "progress": 0,
                "total": 3600,
                "percent": 0
            },
            "timetracking": {
                "originalEstimate": "1h",
                "remainingEstimate": "1h",
                "originalEstimateSeconds": 3600,
                "remainingEstimateSeconds": 3600
            },
            "customfield_10081": null,
            "issuetype": {
                "self": "https://my.jira-instance.com/rest/api/2/issuetype/6",
                "id": "6",
                "description": "",
                "iconUrl": "https://my.jira-instance.com/images/icons/issuetypes/story.png",
                "name": "Story",
                "subtask": false
            },
            "customfield_10080": "11249",
            "timespent": null,
            "reporter": {
                "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                "name": "foo",
                "emailAddress": "foo@rando_company.com",
                "avatarUrls": {
                    "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                    "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                    "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                    "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                },
                "displayName": "foo",
                "active": true
            },
            "updated": "2015-02-06T06:58:43.374-0800",
            "customfield_10180": null,
            "created": "2015-01-02T10:37:27.270-0800",
            "priority": {
                "self": "https://my.jira-instance.com/rest/api/2/priority/4",
                "iconUrl": "https://my.jira-instance.com/images/icons/priorities/minor.png",
                "name": "Medium",
                "id": "4"
            },
            "description": null,
            "customfield_10002": 20.0,
            "issuelinks": [],
            "customfield_10004": null,
            "customfield_10000": null,
            "customfield_11007": null,
            "subtasks": [],
            "status": {
                "self": "https://my.jira-instance.com/rest/api/2/status/10128",
                "description": "Staged",
                "iconUrl": "https://my.jira-instance.com/images/icons/statuses/generic.png",
                "name": "Staged",
                "id": "10128",
                "statusCategory": {
                    "self": "https://my.jira-instance.com/rest/api/2/statuscategory/4",
                    "id": 4,
                    "key": "indeterminate",
                    "colorName": "yellow",
                    "name": "In Progress"
                }
            },
            "labels": [],
            "workratio": 0,
            "project": {
                "self": "https://my.jira-instance.com/rest/api/2/project/10931",
                "id": "10931",
                "key": "jira-project-key",
                "name": "jira-project-key",
                "avatarUrls": {
                    "16x16": "https://my.jira-instance.com/secure/projectavatar?size=xsmall&pid=10931&avatarId=11271",
                    "24x24": "https://my.jira-instance.com/secure/projectavatar?size=small&pid=10931&avatarId=11271",
                    "32x32": "https://my.jira-instance.com/secure/projectavatar?size=medium&pid=10931&avatarId=11271",
                    "48x48": "https://my.jira-instance.com/secure/projectavatar?pid=10931&avatarId=11271"
                },
                "projectCategory": {
                    "self": "https://my.jira-instance.com/rest/api/2/projectCategory/10511",
                    "id": "10511",
                    "description": "TV Display Projects",
                    "name": "TV"
                }
            },
            "aggregateprogress": {
                "progress": 0,
                "total": 3600,
                "percent": 0
            },
            "customfield_11012": null,
            "lastViewed": "2015-02-06T06:58:43.360-0800",
            "components": [],
            "customfield_11010": null,
            "customfield_10010": null,
            "comment": {
                "startAt": 0,
                "maxResults": 0,
                "total": 0,
                "comments": []
            },
            "timeoriginalestimate": 3600,
            "customfield_11014": null,
            "customfield_10681": null,
            "votes": {
                "self": "https://my.jira-instance.com/rest/api/2/issue/jira-project-key-355/votes",
                "votes": 0,
                "hasVoted": false
            },
            "fixVersions": [],
            "resolution": null,
            "resolutiondate": null,
            "creator": {
                "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                "name": "foo",
                "emailAddress": "foo@rando_company.com",
                "avatarUrls": {
                    "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                    "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                    "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                    "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                },
                "displayName": "foo",
                "active": true
            },
            "customfield_10880": null,
            "aggregatetimeoriginalestimate": 3600,
            "customfield_10884": null,
            "customfield_10883": null,
            "customfield_10881": null,
            "duedate": null,
            "customfield_10020": null,
            "customfield_10782": null,
            "customfield_10781": "2015-01-30",
            "customfield_10780": null,
            "watches": {
                "self": "https://my.jira-instance.com/rest/api/2/issue/jira-project-key-355/watchers",
                "watchCount": 1,
                "isWatching": true
            },
            "worklog": {
                "startAt": 0,
                "maxResults": 20,
                "total": 0,
                "worklogs": []
            },
            "assignee": {
                "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                "name": "foo",
                "emailAddress": "foo@rando_company.com",
                "avatarUrls": {
                    "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                    "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                    "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                    "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                },
                "displayName": "foo",
                "active": true
            },
            "attachment": [{
                "self": "https://my.jira-instance.com/rest/api/2/attachment/13041",
                "id": "13041",
                "filename": "jan_5.jpg",
                "author": {
                    "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                    "name": "foo",
                    "emailAddress": "foo@rando_company.com",
                    "avatarUrls": {
                        "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                        "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                        "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                        "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                    },
                    "displayName": "foo",
                    "active": true
                },
                "created": "2015-01-02T10:37:37.802-0800",
                "size": 143252,
                "mimeType": "image/jpeg",
                "content": "https://my.jira-instance.com/secure/attachment/13041/jan_5.jpg",
                "thumbnail": "https://my.jira-instance.com/secure/thumbnail/13041/_thumb_13041.png"
            }, {
                "self": "https://my.jira-instance.com/rest/api/2/attachment/13250",
                "id": "13250",
                "filename": "ThisWeek_Feb2.jpg",
                "author": {
                    "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                    "name": "foo",
                    "emailAddress": "foo@rando_company.com",
                    "avatarUrls": {
                        "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                        "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                        "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                        "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                    },
                    "displayName": "foo",
                    "active": true
                },
                "created": "2015-01-30T10:31:40.641-0800",
                "size": 274703,
                "mimeType": "image/jpeg",
                "content": "https://my.jira-instance.com/secure/attachment/13250/ThisWeek_Feb2.jpg",
                "thumbnail": "https://my.jira-instance.com/secure/thumbnail/13250/_thumb_13250.png"
            }, {
                "self": "https://my.jira-instance.com/rest/api/2/attachment/13087",
                "id": "13087",
                "filename": "ThisWeek_jan12.jpg",
                "author": {
                    "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                    "name": "foo",
                    "emailAddress": "foo@rando_company.com",
                    "avatarUrls": {
                        "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                        "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                        "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                        "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                    },
                    "displayName": "foo",
                    "active": true
                },
                "created": "2015-01-12T08:18:40.652-0800",
                "size": 121908,
                "mimeType": "image/jpeg",
                "content": "https://my.jira-instance.com/secure/attachment/13087/ThisWeek_jan12.jpg",
                "thumbnail": "https://my.jira-instance.com/secure/thumbnail/13087/_thumb_13087.png"
            }, {
                "self": "https://my.jira-instance.com/rest/api/2/attachment/13147",
                "id": "13147",
                "filename": "ThisWeek_jan19.png",
                "author": {
                    "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                    "name": "foo",
                    "emailAddress": "foo@rando_company.com",
                    "avatarUrls": {
                        "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                        "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                        "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                        "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                    },
                    "displayName": "foo",
                    "active": true
                },
                "created": "2015-01-19T09:40:58.930-0800",
                "size": 2339087,
                "mimeType": "image/png",
                "content": "https://my.jira-instance.com/secure/attachment/13147/ThisWeek_jan19.png",
                "thumbnail": "https://my.jira-instance.com/secure/thumbnail/13147/_thumb_13147.png"
            }, {
                "self": "https://my.jira-instance.com/rest/api/2/attachment/13189",
                "id": "13189",
                "filename": "ThisWeek-Jan26.jpg",
                "author": {
                    "self": "https://my.jira-instance.com/rest/api/2/user?username=foo",
                    "name": "foo",
                    "emailAddress": "foo@rando_company.com",
                    "avatarUrls": {
                        "16x16": "https://my.jira-instance.com/secure/useravatar?size=xsmall&ownerId=foo&avatarId=11062",
                        "24x24": "https://my.jira-instance.com/secure/useravatar?size=small&ownerId=foo&avatarId=11062",
                        "32x32": "https://my.jira-instance.com/secure/useravatar?size=medium&ownerId=foo&avatarId=11062",
                        "48x48": "https://my.jira-instance.com/secure/useravatar?ownerId=foo&avatarId=11062"
                    },
                    "displayName": "foo",
                    "active": true
                },
                "created": "2015-01-23T09:55:32.198-0800",
                "size": 138201,
                "mimeType": "image/jpeg",
                "content": "https://my.jira-instance.com/secure/attachment/13189/ThisWeek-Jan26.jpg",
                "thumbnail": "https://my.jira-instance.com/secure/thumbnail/13189/_thumb_13189.png"
            }],
            "aggregatetimeestimate": 3600,
            "versions": [],
            "timeestimate": 3600,
            "aggregatetimespent": null,
            "customfield_10070": null
        }
    },
    "changelog": {
        "id": "219580",
        "items": [{
            "field": "status",
            "fieldtype": "jira",
            "from": "10127",
            "fromString": "Submitted",
            "to": "10128",
            "toString": "Staged"
        }]
    },
    "timestamp": 1423234723378
}

我的问题是,减少 POST 有效负载中的数据以适合我的模型的首选方法是什么?我应该重构我的模型以匹配 webhook JSON 吗?或者我应该使用预保存挂钩来解析我想要的属性,然后 return 解析有效负载?或者我应该覆盖 webhook 对象上的保存方法来解析我需要的数据然后只保存我需要的位吗?

我尝试创建一个简单的序列化程序,仅初始化几个字段并将整个有效负载扔给它以查看有什么问题,但没有任何内容被保存。

这实际上取决于您尝试对收集到的数据执行的操作。 创建映射 class 如果仅用于数据存储目的,将是更好的解决方案。

class JiraWebhookMapper(object):
    def map(data):
        return {'user_id': data.get("user").get("id") ....}


mapped_data = JiraWebhookMapper().map(response.content)
WebHook.objects.create(**mapped_data)