DRF - 使用多个外键序列化模型

时间:2017-02-21 07:55:50

标签: python django django-rest-framework relationship

我正在研究Django中的CRUD API,我需要序列化两个表中的外键的模型。该模型在两个一对多关系的“多”方面,并没有真正看到在此模型中指定关系的任何其他方式(我是python和Django的新手,我正在使用Django-Rest-Framework用于创建API)

所以,我有两个问题:

1 - Is it a good Idea to have multiple foreign keys in my model or I should refractor my relationships some other way?

2 - If it is fine to have multiple foreign keys in a single model, how do I serialize the model to return the proper JSON?

我的模型是这样的(还有一些字段):

class DataSource(models.Model):
    datasource_name = models.CharField(max_length=50, unique=True)
    datasource_description = models.CharField(max_length=100)
    ...

class Campaign(models.Model):
    name = models.CharField(max_length=200)
    subject = models.CharField(max_length=200)
    sender = models.EmailField(max_length=200)
    ...

class CampaignDeliveries(models.Model):
    campaign_id = models.ForeignKey(Campaign)
    datasource_id = models.ForeignKey(DataSource)
    delivery_reference_id = models.CharField(max_length=200, primary_key=True)
    date_sent = models.DateTimeField()

交货记录引用了已进行交货的广告系列以及为该交货选择的数据来源。

必须以如下格式返回数据:

{
    campaign_id: 001,
    datasource_id: 002,
    datasource_name: "Data Source Name",
    campaign_name: "Campaign Name"
    setup_date:"<Setup Date>",
    delivery_history:[{
        delivery_reference_id:DL_001,
        sender : "abc@xyz.com",
        subject : "Subject",
        sent_on : "<Date>"
    },
    {
        delivery_reference_id:DL_002,
        sender : "abc@xyz.com",
        subject : "Subject",
        sent_on : "<Date>"
    },
    {
        delivery_reference_id:DL_003,
        sender : "abc@xyz.com",
        subject : "Subject",
        sent_on : "<Date>"
    }
    ....
    ]
}

datasource_idcampaign_id字段是django在创建记录时为记录提供的默认ID,delivery_reference_id是在创建传递记录时分配的自定义ID。 / p>

我希望我已经说清楚了。但是,请询问是否有不清楚的事情。

2 个答案:

答案 0 :(得分:0)

通常您将ForeignKey字段命名为:

class CampaignDelivery(models.Model):
    campaign = models.ForeignKey('Campaign')

字段campaign_id会自动添加,并且是对存储广告系列ID的表字段的引用。我经常会很有用。因此CampaignDelivery.campaign会返回django对象,而CampaignDelivery.campaign_id会返回引用广告系列的ID。

在一个模型中有多个外键没有错,但我不确定你想在这里完成什么。我认为您可以获取Campaign数据及其交付历史记录。 您提供的响应示例对此并不是非常好,因为它意味着可以将一个传递分配给多个广告系列(由于您拥有ForeignKey,这不是真的)。你可以这样做:

from rest_framework import serializers

class CampaignDeliverySerializer(serializers.ModelSerializer):

    class Meta:
        model = CampaignDelivery
        fields = ('date_sent', 'datasource_id', 'delivery_reference_id', 'datasource__datasource_name', ...)

class CampaignSerializer(serialziers.ModelSerializer):
    delivery_history = CampaignDeliverySerializer(
                           source='campaigndeliveries_set', 
                           many=True
                       )

    class Meta:
        model = Campaign
        fields = ('id', 'name', 'sender', 'subject', 'delivery_history', ...)

回复示例:

{
    'campaign': {
        'id': 123,
        'name': 'Best campaign name evar',
        'sender': 'foo@bar.com',
        'subject': 'Campaign subject',
        'delivery_history': [
            {
                'date_sent': '2017-02-22',
                'datasource_id': 321,
                'delivery_reference_id': 'DL_001',
                'datasource__datasource_name': 'Datasource name'
            },
            ...
        ]
    }
}

答案 1 :(得分:-1)

1)您认为如何根据自己的逻辑对模型进行FK,但在本例中我的方法就是这样做。

2)这是答案:

默认情况下,您必须将每个FK的related_name命名为主模型。

models.py

class CampaignDeliveries(models.Model):
    delivery_reference_id = models.CharField(max_length=200, primary_key=True)
    date_sent = models.DateTimeField()


class DataSource(models.Model):
    datasource_name = models.CharField(max_length=50, unique=True)
    datasource_description = models.CharField(max_length=100)
    campain_id = models.ForeignKey(CampaignDeliveries, related_name='data_source')

class Campaign(models.Model):
    name = models.CharField(max_length=200)
    subject = models.CharField(max_length=200)
    sender = models.EmailField(max_length=200)
    campain_id = models.ForeignKey(CampaignDeliveries, related_name='campaign_source')

serialiers.py

class DataSourceSerilaizer(serializers.ModelSerializer)

    class Meta:
        model = DataSource
        fileds = '__all__'


class CampaignSerilaizer(serializers.ModelSerializer)

    class Meta:
        model = Campaign
        fileds = '__all__'


class CampaignDeliveriesSerilaizer(serializers.ModelSerializer):

    campaign_source = CampaignSerilaizer(many=True)
    data_source = DataSourceSerilaizer(many=True)

    class Meta:
        model = CampaignDeliveries
        fileds = '__all__'

viwes.py

qv = CampaignDeliveries.objects.all()
serializer = CampaignDeliveriesSerilaizer(qv)
print (serializer.data)