django DRF.从父类API路由中过滤通过ForeignKey链接到parrent的子类对象

lvmkulzt  于 2023-05-30  发布在  Go
关注(0)|答案(1)|浏览(124)

我在一些电子商务商店工作(只是为了学习)。我有父模型Category和子模型Product,它有一个字段category,该字段引用Category对象Many-To-One relations (ForeignKey)。方法是从父类进行过滤,例如:Category检索与给定参数匹配的所有Product对象。
例如:当我发送一个路由"localhost/api/categories/"的请求时,我得到了所有的类别和子类别(只是为了更广泛的视野:子类别路由也起作用。如果我向localhost/api/categories/smartphones/发送请求,它将返回一个包含子类别的响应,这些子类别是smartphones的子类别,依此类推。现在我想用这种方式实现过滤:当我发送一个路由"localhost/api/categories/smartphones/brand?=apple"的请求时,它必须返回所有Product字段等于“apple”的Product对象。这个模式必须适用于任何类别,所以我不必为可能包含Apple设备的每个类别将apple硬编码为Category对象。
我现在的代码(不是所有行都包括在内,但最重要的是):

产品/models.py

class Product(models.Model):
"""Model representing a product."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=255)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
brand = models.ForeignKey('Brand', on_delete=models.CASCADE, related_name='products')
slug = models.SlugField(unique=True, blank=True, default=id)

class Brand(models.Model):
    """A model representing the brand of the product."""
    id = models.AutoField(primary_key=True, editable=False)
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True, editable=False)

产品/serializers.py

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

产品/views.py

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    lookup_field = 'slug'

产品/urls.py

router = DefaultRouter()
router.register("", ProductViewSet)

urlpatterns = [
    path("", include(router.urls)),
]

类别/models.py

class Category(MPTTModel):
""" Category model inherits from a side application class MPTT designed for more
convenient work with model tree structure """

objects = CategoryManager()  # Use of a custom manager defined above

id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=120, db_index=True, unique=True)
slug = models.SlugField(unique=True)
parent = TreeForeignKey(   # MPTT model Field represents a parent of subcategory (if exists) in tree structure.
    "self",
    blank=True,
    null=True,
    related_name="child",
    on_delete=models.CASCADE
)

类别/serializers.py

class RecursiveField(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data

class CategorySerializer(serializers.ModelSerializer):
    child = RecursiveField(many=True, read_only=True)

categories/views.pyclass CategoriesAPIViewSet(viewsets.ModelViewSet):

""" Standard ModelViewSet which implements CRUD with minor changes. """

queryset = Category.objects.all()
serializer_class = CategorySerializer
lookup_field = 'slug'

类别/urls.py

router = SimpleRouter()

router.register("", CategoriesAPIViewSet)

urlpatterns += router.urls
wribegjk

wribegjk1#

正如在www.example.com中提到https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset,您可以实现get_queryset方法来根据请求提供不同的查询集。
您可以使用self.request.query_params访问已发送的brand,网址:https://www.django-rest-framework.org/api-guide/requests/#query_params
所以你的方法可能看起来像这样:

def get_queryset(self):
  return Product.objects.filter(brand=self.request.query_params['brand'])

或类似:)
根据评论编辑:
如果查询参数是可选的,您可以这样做:

def get_queryset(self):
  if 'brand' in self.request.query_params:
    return Product.objects.filter(brand=self.request.query_params['brand'])
  return Product.objects.all()

相关问题