DRF. Filtering child's class objects linked to parrent with ForeignKey from a parent class api routing

huangapple go评论72阅读模式
英文:

DRF. Filtering child's class objects linked to parrent with ForeignKey from a parent class api routing

问题

I've translated the code-related parts of your text:

products/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)

products/serializers.py

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

products/views.py

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

products/urls.py

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

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

categories/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(
        "self",
        blank=True,
        null=True,
        related_name="child",
        on_delete=models.CASCADE
    )

categories/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.py

class CategoriesAPIViewSet(viewsets.ModelViewSet):
    """Standard ModelViewSet which implements CRUD with minor changes."""
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    lookup_field = 'slug'

categories/urls.py

router = SimpleRouter()
router.register("", CategoriesAPIViewSet)

urlpatterns += router.urls

These translations should help you understand and work with the code in a Chinese context.

英文:

I work on some kind of e-commercial shop (just for learning purpose).
I have parent model Category and child model Product which has a field category which references to Category object with Many-To-One relations (ForeignKey).
Idea is to make filtration from a parent class e.g. Category to retrieve all Product objects matches with given paramenter(s).

For example:
When I send a request to route "localhost/api/categories/" I get all categories and subcategories (just for wider vision: subcategory routing also works. If i send request to localhost/api/categories/smartphones/ it returns a response with subcategories which are children of smartphones and so on).
Now I want to implement filtering in such way : when I send a request to route "localhost/api/categories/smartphones/brand?=apple" it has to return all Product objects with brand field equal to "apple". And this pattern has to work for any category so I don't have to hardcode apple as Category object for every single category that might contain Apple devices.

My code right now (not all lines included but most important) :

products/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)

products/serializers.py

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

products/views.py

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

products/urls.py

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

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

categories/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
)

categories/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.py
class CategoriesAPIViewSet(viewsets.ModelViewSet):

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

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

categories/urls.py

router = SimpleRouter()

router.register("", CategoriesAPIViewSet)

urlpatterns += router.urls

答案1

得分: 0

如下所述: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()
英文:

As mentioned at https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset , you can implement the get_queryset method to provide a different queryset based on the request.

You can use self.request.query_params to access the brand that has been sent, https://www.django-rest-framework.org/api-guide/requests/#query_params

So your method might look like:

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

Or similar DRF. Filtering child's class objects linked to parrent with ForeignKey from a parent class api routing

EDIT based on comment:

If the query param is optional, you could do this:

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()

huangapple
  • 本文由 发表于 2023年5月24日 22:11:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324497.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定