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

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

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

  1. class Product(models.Model):
  2. """Model representing a product."""
  3. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  4. name = models.CharField(max_length=255)
  5. category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
  6. brand = models.ForeignKey('Brand', on_delete=models.CASCADE, related_name='products')
  7. slug = models.SlugField(unique=True, blank=True, default=id)
  8. class Brand(models.Model):
  9. """A model representing the brand of the product."""
  10. id = models.AutoField(primary_key=True, editable=False)
  11. name = models.CharField(max_length=255)
  12. slug = models.SlugField(unique=True, editable=False)

products/serializers.py

  1. class ProductSerializer(serializers.ModelSerializer):
  2. class Meta:
  3. model = Product
  4. fields = '__all__'

products/views.py

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

products/urls.py

  1. router = DefaultRouter()
  2. router.register("", ProductViewSet)
  3. urlpatterns = [
  4. path("", include(router.urls)),
  5. ]

categories/models.py

  1. class Category(MPTTModel):
  2. """Category model inherits from a side application class MPTT designed for more
  3. convenient work with model tree structure."""
  4. objects = CategoryManager() # Use of a custom manager defined above
  5. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  6. name = models.CharField(max_length=120, db_index=True, unique=True)
  7. slug = models.SlugField(unique=True)
  8. parent = TreeForeignKey(
  9. "self",
  10. blank=True,
  11. null=True,
  12. related_name="child",
  13. on_delete=models.CASCADE
  14. )

categories/serializers.py

  1. class RecursiveField(serializers.Serializer):
  2. def to_representation(self, value):
  3. serializer = self.parent.parent.__class__(value, context=self.context)
  4. return serializer.data
  5. class CategorySerializer(serializers.ModelSerializer):
  6. child = RecursiveField(many=True, read_only=True)

categories/views.py

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

categories/urls.py

  1. router = SimpleRouter()
  2. router.register("", CategoriesAPIViewSet)
  3. 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

  1. class Product(models.Model):
  2. """Model representing a product."""
  3. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  4. name = models.CharField(max_length=255)
  5. category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
  6. brand = models.ForeignKey('Brand', on_delete=models.CASCADE, related_name='products')
  7. slug = models.SlugField(unique=True, blank=True, default=id)
  8. class Brand(models.Model):
  9. """A model representing the brand of the product."""
  10. id = models.AutoField(primary_key=True, editable=False)
  11. name = models.CharField(max_length=255)
  12. slug = models.SlugField(unique=True, editable=False)

products/serializers.py

  1. class ProductSerializer(serializers.ModelSerializer):
  2. class Meta:
  3. model = Product
  4. fields = '__all__'

products/views.py

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

products/urls.py

  1. router = DefaultRouter()
  2. router.register("", ProductViewSet)
  3. urlpatterns = [
  4. path("", include(router.urls)),
  5. ]

categories/models.py

  1. class Category(MPTTModel):
  2. """ Category model inherits from a side application class MPTT designed for more
  3. convenient work with model tree structure """
  4. objects = CategoryManager() # Use of a custom manager defined above
  5. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  6. name = models.CharField(max_length=120, db_index=True, unique=True)
  7. slug = models.SlugField(unique=True)
  8. parent = TreeForeignKey( # MPTT model Field represents a parent of subcategory (if exists) in tree structure.
  9. "self",
  10. blank=True,
  11. null=True,
  12. related_name="child",
  13. on_delete=models.CASCADE
  14. )

categories/serializers.py

  1. class RecursiveField(serializers.Serializer):
  2. def to_representation(self, value):
  3. serializer = self.parent.parent.__class__(value, context=self.context)
  4. return serializer.data
  5. class CategorySerializer(serializers.ModelSerializer):
  6. child = RecursiveField(many=True, read_only=True)

categories/views.py
class CategoriesAPIViewSet(viewsets.ModelViewSet):

  1. """ Standard ModelViewSet which implements CRUD with minor changes. """
  2. queryset = Category.objects.all()
  3. serializer_class = CategorySerializer
  4. lookup_field = 'slug'

categories/urls.py

  1. router = SimpleRouter()
  2. router.register("", CategoriesAPIViewSet)
  3. 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

因此,您的方法可能如下所示:

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

或类似的方法。

根据评论进行编辑:

如果查询参数是可选的,您可以这样做:

  1. def get_queryset(self):
  2. if 'brand' in self.request.query_params:
  3. return Product.objects.filter(brand=self.request.query_params['brand'])
  4. 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:

  1. def get_queryset(self):
  2. 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:

  1. def get_queryset(self):
  2. if 'brand' in self.request.query_params:
  3. return Product.objects.filter(brand=self.request.query_params['brand'])
  4. 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:

确定