Python 如何在Django REST Framework ModelSerializer的创建函数中使用field.set()?
我有一个名为Python 如何在Django REST Framework ModelSerializer的创建函数中使用field.set()?,python,django,django-rest-framework,Python,Django,Django Rest Framework,我有一个名为RoomMarket的中间模型,连接两个相关模型市场-房间市场-房间。当我试图使用可写嵌套序列化程序插入RoomMarket的记录时,我遇到了一个错误: /room_markets/ 禁止直接分配到多对多集合的前端。改为使用regions.set() 这是我简化的模型.py: class RecordStatus: published = 'Published' drafted = 'Drafted' hidden = 'Hidden' status
RoomMarket
的中间模型,连接两个相关模型<代码>市场-房间市场
-房间
。当我试图使用可写嵌套序列化程序插入RoomMarket
的记录时,我遇到了一个错误:
/room_markets/禁止直接分配到多对多集合的前端。改为使用regions.set() 这是我简化的
模型.py
:
class RecordStatus:
published = 'Published'
drafted = 'Drafted'
hidden = 'Hidden'
status = [
(published, 'Published'),
(drafted, 'Drafted'),
(hidden, 'Hidden'),
]
class Market(models.Model, RecordStatus):
name = models.CharField(max_length=100)
regions = models.ManyToManyField(Region)
languages = models.ManyToManyField(Language)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
@property
def get_product_variations(self):
return Product.objects.filter(distributor__region__market=self).distinct().count()
class Room(models.Model, RecordStatus):
style = models.ForeignKey(Style, on_delete=models.CASCADE)
markets = models.ManyToManyField(Market, through='RoomMarket')
image = models.ImageField(upload_to='room_images', width_field=None, height_field=None,
max_length=250, null=True, blank=True)
name = models.CharField(max_length=50)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
class RoomMarket(models.Model):
market = models.ForeignKey(Market, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
landing_page = models.BooleanField(blank=True, null=True)
def __str__(self):
return '%s - %s' % (self.market, self.room)
class CustomRelatedField(serializers.RelatedField):
def display_value(self, instance):
return instance
def to_representation(self, value):
return str(value)
def to_internal_value(self, data):
model = self.queryset.model
return model.objects.get(id=data)
class MarketSerializer(serializers.ModelSerializer):
regions = CustomRelatedField(many=True, queryset=Region.objects.all())
languages = CustomRelatedField(many=True, queryset=Language.objects.all())
variation = serializers.ReadOnlyField(source='get_product_variations')
landing_page = serializers.SerializerMethodField(source='get_landing_page')
class Meta:
model = Market
fields = ['id', 'regions', 'languages', 'name', 'status', 'variation', 'landing_page']
depth = 1
@staticmethod
def get_landing_page(market):
queryset = RoomMarket.objects.filter(market=market)
if queryset.exists():
for r in queryset:
return r.room.id
else:
return '-'
class RoomSerializer(serializers.ModelSerializer):
style = CustomRelatedField(many=False, queryset=Style.objects.all())
markets = CustomRelatedField(many=True, queryset=Market.objects.all())
class Meta:
model = Room
fields = ['id', 'markets', 'style', 'image', 'name', 'status']
class RoomMarketSerializer(serializers.ModelSerializer):
market = MarketSerializer()
room = CustomRelatedField(many=False, queryset=Room.objects.all())
class Meta:
model = RoomMarket
fields = ['id', 'market', 'room', 'landing_page']
def create(self, validated_data):
# create market data for Market model.
market_data = validated_data.pop('market')
market = Market.objects.create(**market_data)
# create RoomMarket and set market FK.
room_market = RoomMarket.objects.create(market=market, **validated_data)
# return RoomMarket instance.
return room_market
class RoomMarketView(viewsets.ModelViewSet):
permission_classes = [permissions.DjangoModelPermissions]
queryset = RoomMarket.objects.all()
serializer_class = RoomMarketSerializer
这是我的序列化程序.py
:
class RecordStatus:
published = 'Published'
drafted = 'Drafted'
hidden = 'Hidden'
status = [
(published, 'Published'),
(drafted, 'Drafted'),
(hidden, 'Hidden'),
]
class Market(models.Model, RecordStatus):
name = models.CharField(max_length=100)
regions = models.ManyToManyField(Region)
languages = models.ManyToManyField(Language)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
@property
def get_product_variations(self):
return Product.objects.filter(distributor__region__market=self).distinct().count()
class Room(models.Model, RecordStatus):
style = models.ForeignKey(Style, on_delete=models.CASCADE)
markets = models.ManyToManyField(Market, through='RoomMarket')
image = models.ImageField(upload_to='room_images', width_field=None, height_field=None,
max_length=250, null=True, blank=True)
name = models.CharField(max_length=50)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
class RoomMarket(models.Model):
market = models.ForeignKey(Market, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
landing_page = models.BooleanField(blank=True, null=True)
def __str__(self):
return '%s - %s' % (self.market, self.room)
class CustomRelatedField(serializers.RelatedField):
def display_value(self, instance):
return instance
def to_representation(self, value):
return str(value)
def to_internal_value(self, data):
model = self.queryset.model
return model.objects.get(id=data)
class MarketSerializer(serializers.ModelSerializer):
regions = CustomRelatedField(many=True, queryset=Region.objects.all())
languages = CustomRelatedField(many=True, queryset=Language.objects.all())
variation = serializers.ReadOnlyField(source='get_product_variations')
landing_page = serializers.SerializerMethodField(source='get_landing_page')
class Meta:
model = Market
fields = ['id', 'regions', 'languages', 'name', 'status', 'variation', 'landing_page']
depth = 1
@staticmethod
def get_landing_page(market):
queryset = RoomMarket.objects.filter(market=market)
if queryset.exists():
for r in queryset:
return r.room.id
else:
return '-'
class RoomSerializer(serializers.ModelSerializer):
style = CustomRelatedField(many=False, queryset=Style.objects.all())
markets = CustomRelatedField(many=True, queryset=Market.objects.all())
class Meta:
model = Room
fields = ['id', 'markets', 'style', 'image', 'name', 'status']
class RoomMarketSerializer(serializers.ModelSerializer):
market = MarketSerializer()
room = CustomRelatedField(many=False, queryset=Room.objects.all())
class Meta:
model = RoomMarket
fields = ['id', 'market', 'room', 'landing_page']
def create(self, validated_data):
# create market data for Market model.
market_data = validated_data.pop('market')
market = Market.objects.create(**market_data)
# create RoomMarket and set market FK.
room_market = RoomMarket.objects.create(market=market, **validated_data)
# return RoomMarket instance.
return room_market
class RoomMarketView(viewsets.ModelViewSet):
permission_classes = [permissions.DjangoModelPermissions]
queryset = RoomMarket.objects.all()
serializer_class = RoomMarketSerializer
这是我的视图。py
:
class RecordStatus:
published = 'Published'
drafted = 'Drafted'
hidden = 'Hidden'
status = [
(published, 'Published'),
(drafted, 'Drafted'),
(hidden, 'Hidden'),
]
class Market(models.Model, RecordStatus):
name = models.CharField(max_length=100)
regions = models.ManyToManyField(Region)
languages = models.ManyToManyField(Language)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
@property
def get_product_variations(self):
return Product.objects.filter(distributor__region__market=self).distinct().count()
class Room(models.Model, RecordStatus):
style = models.ForeignKey(Style, on_delete=models.CASCADE)
markets = models.ManyToManyField(Market, through='RoomMarket')
image = models.ImageField(upload_to='room_images', width_field=None, height_field=None,
max_length=250, null=True, blank=True)
name = models.CharField(max_length=50)
status = models.CharField(max_length=20, choices=RecordStatus.status, default=RecordStatus.published)
class RoomMarket(models.Model):
market = models.ForeignKey(Market, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
landing_page = models.BooleanField(blank=True, null=True)
def __str__(self):
return '%s - %s' % (self.market, self.room)
class CustomRelatedField(serializers.RelatedField):
def display_value(self, instance):
return instance
def to_representation(self, value):
return str(value)
def to_internal_value(self, data):
model = self.queryset.model
return model.objects.get(id=data)
class MarketSerializer(serializers.ModelSerializer):
regions = CustomRelatedField(many=True, queryset=Region.objects.all())
languages = CustomRelatedField(many=True, queryset=Language.objects.all())
variation = serializers.ReadOnlyField(source='get_product_variations')
landing_page = serializers.SerializerMethodField(source='get_landing_page')
class Meta:
model = Market
fields = ['id', 'regions', 'languages', 'name', 'status', 'variation', 'landing_page']
depth = 1
@staticmethod
def get_landing_page(market):
queryset = RoomMarket.objects.filter(market=market)
if queryset.exists():
for r in queryset:
return r.room.id
else:
return '-'
class RoomSerializer(serializers.ModelSerializer):
style = CustomRelatedField(many=False, queryset=Style.objects.all())
markets = CustomRelatedField(many=True, queryset=Market.objects.all())
class Meta:
model = Room
fields = ['id', 'markets', 'style', 'image', 'name', 'status']
class RoomMarketSerializer(serializers.ModelSerializer):
market = MarketSerializer()
room = CustomRelatedField(many=False, queryset=Room.objects.all())
class Meta:
model = RoomMarket
fields = ['id', 'market', 'room', 'landing_page']
def create(self, validated_data):
# create market data for Market model.
market_data = validated_data.pop('market')
market = Market.objects.create(**market_data)
# create RoomMarket and set market FK.
room_market = RoomMarket.objects.create(market=market, **validated_data)
# return RoomMarket instance.
return room_market
class RoomMarketView(viewsets.ModelViewSet):
permission_classes = [permissions.DjangoModelPermissions]
queryset = RoomMarket.objects.all()
serializer_class = RoomMarketSerializer
我用于发布数据的JSON格式:
{
"market": {
"regions": [1,2],
"languages": [1,2],
"name": "Asia",
"status": "Published"
},
"room": 2,
"landing_page": true
}
我已经读过一些关于这个问题的SO问题,但大多数情况下都是在
ModelSerializer
类中的Form/View而不是create
函数上。我应该在中间模型ModelSerializer
类的create
函数中更改什么?问题是,当您创建market
实例时,您将region
和language
对象传递给create()
方法。您应该将其传递给set()
:
def create(self, validated_data):
# create market data for Market model.
market_data = validated_data.pop('market')
regions = market_data.pop("regions")
languages = market_data.pop("languages")
market = Market.objects.create(**market_data)
market.regions.set(regions)
market.languages.set(languages)
谢谢@neverwanner向我解释。我可以将此应用于
更新
功能吗?因为我确信我还需要明确定义update
函数。@Nathan欢迎!当然你可以在更新中使用它。但是请注意,set()
替换相关对象集。如果您不需要它,可能最好在update()
中使用add()
。有关更多详细信息,请查看文档的相关部分: