问题
Previous topic where I was kindly helped by @gasman so i have a model class ingredients like:
@register_model_chooser
class Ingredient(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
and to represent this in API i created this class:
class IngredientChooserBlock(ModelChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'name': value.name,
}
then i have another model class that uses IngredientChooserBlock
class:
@register_model_chooser
class Menu(models.Model):
ingredient = StreamField([
('zutaten', IngredientChooserBlock('kitchen.Ingredient')) ],
null=True, verbose_name='', blank=True)
def __str__(self):
return self.title
and because i need this ingredient
in my API i created same model class to overwrite get_api_representation
:
class WeekChooserBlock(ModelChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'ingredients': value.ingredient,
}
and in the end in my main model class I'm trying to use this WeekChooserBlock
which takes kitchen.Menu
as argument like so:
class Week(models.Model):
dishes_sp = StreamField([
('menu', WeekChooserBlock('kitchen.Menu')) ],
null=True, verbose_name='', blank=True)
The problem is that it prints out an error in DRF like this:
Object of type 'StreamValue' is not JSON serializable
Didn't want to create too big question, but for greater clarity i have actually another objects in my Menu
class like:
class Menu(models.Model):
title = models.CharField(max_length=255)
image = models.URLField(blank=True, null=True)
price = models.FloatField(blank=True, null=True, max_length=255)
ingredient = StreamField([
('zutaten', IngredientChooserBlock('kitchen.Ingredient')) ],
null=True, verbose_name='', blank=True)
steps = StreamField([
('Schritt', TextBlock())
], null=True, verbose_name='Vorbereitungsschritte', blank=True)
and I'm also trying to represent them too. But the error is displayed only if I'm trying to output StreamField
class WeekChooserBlock(ModelChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'title': value.title,
'picture': value.image,
'price': value.price,
'ingredients': value.ingredient,
'steps': value.steps
}
Thanks for your support!
回答1:
The problem here is that you're returning {'ingredients': value.ingredient}
from WeekChooserBlock.get_api_representation
. Here value.ingredient
is a StreamValue instance, which is a complex Wagtail-specific object containing methods for template rendering, as well as the actual stream data - DRF doesn't know how to handle this complex object.
You need to ensure that your get_api_representation
response only consists of standard Python types, such as strings and dicts. For example:
class WeekChooserBlock(ModelChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'ingredients': [ingredient.value['name'] for ingredient in value.ingredient],
}
If you want to re-use the API representation for Ingredient that you defined in IngredientChooserBlock.get_api_representation
, it gets a bit tricker, but you should be able to do this with:
class WeekChooserBlock(ModelChooserBlock):
def get_api_representation(self, value, context=None):
if value:
ingredient = value.ingredient
return ingredient.stream_block.get_api_representation(ingredient, context=context)
来源:https://stackoverflow.com/questions/45934876/converting-class-object-to-readable-value-for-get-api-representation-function