使用Django Rest Framework基于参数动态序列化对象的最佳方式



我想使用中间模型和自定义query_param来呈现动态选择的对象。

例如,我想进行这样的查询:

http://api.url/v1/recipes/19/?location=1,并根据位置获取带有其成分的序列化Recipe对象,发送为query_params:

配方对象:

{
"id": 19,
"ingredients": [
{
"id": 35,           # Product id
"name": "Tomato",   # Product name
"price": 2.0,       # Product price
"quantity": 3,
"supplier": 12,     # Supplier at location=1
},
{
"id": 36,           # Product id
"name": "Cheese",   # Product name
"price": 5.0,       # Product price
"quantity": 2,
"supplier": 12,
},
],
"title": "Pizza"
}

如果我更改?location=查询参数,我希望获得相同的配方,但获得另一个供应商的产品。

这是我当前的模式。但任何建议都非常感谢:

class Recipe(models.Model):
title = models.CharField(max_length=255)
class IngredientRecipe(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
quantity = models.FloatField(default=0.0)
product_name = models.CharField(max_length=255)
class Meta:
unique_together = ['product_name', 'recipe']
class Supplier(models.Model):
name = models.CharField(_('Name'), max_length=255)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
class Product(models.Model):
name = models.CharField(max_length=255)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
price = models.FloatField()

我正试图根据供应商的位置将Recipe对象及其相关成分序列化:

class IngredientSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class RecipeSerializer(serializers.ModelSerializer):
ingredients = serializers.SerializerMethodField()
class Meta:
model = Recipe
fields = '__all__'
def get_ingredients(self, obj):
location_id = self.context['request'].query_params.get('location', None)
product_names = IngredientRecipe.objects.filter(recipe__id=obj.id).values_list('product_name')
# Here I got the related Products by name and if specified, the supplier's location:
if location_id:
qs = Product.objects.filter(
(Q(supplier__location_id=location_id) | Q(supplier_id__isnull=True)) &
Q(is_active=True) & Q(name__in=product_names)).values_list('id', 'name', 'price')
else:
qs = Product.objects.filter(Q(is_active=True) & Q(name__in=product_names)).values_list('id', 'name',
                             'price')

# Here I try to remove the duplicates and keed the cheapest price:
duplicated_qs = list(set(qs))
duplicated_qs = sorted(duplicated_qs, key=lambda tup: tup[2])
keep = set()
res = []
for sub in duplicated_qs:
if sub[1] not in keep:
res.append(sub)
keep.add(sub[1])
ingredients_ids = [item[0] for item in res]
# Once I have a product list I want to serialize it with the quantity information
# and here is where I got stuck, cause I don't know how to render the context passed. 
qs = Product.objects.filter(id__in=ingredients_ids)
serializer = IngredientSerializer(qs, many=True, context={'quantity': obj.quantity})
return serializer.data

提前感谢大家!

我通常这样做,通过重写get_queryset方法:

# In your view:
class RecipeView(viewsets.ModelViewSet):
def get_queryset(self):
result = Recipe.objects.all()
location = self.request.GET.get("location", None)
if location:
result = result.filter(location__id=location)
return result

最新更新