Andrew Louis
Andrew Louis

Reputation: 390

Django filter ManyToMany filed in query

I need to filter field with ManyToMany in queryset. There must stay only active Products

class Product(model.Model):
    name = models.CharField()
    active = models.BooleanField(blank=True, default=True)


class Package(model.Model):
    name = models.CharField()
    products = models.ManyToManyField(Product)

I tried something like this.

packages = Package.objects.all()
for package in packages:
    active_products = package.products.filter(active=True)
    package.products = active_products

but it updates my packages in database, when i need only change queryset.

expectation concept (do not really need nested structure, query set is fine):

 packages = [
    {'id': 1, 'name': 'First package', 'products': [
        {'id': 1, 'name': 'first product', 'active': True},
        {'id': 2, 'name': 'second product', 'active': True},
    ]},
    {'id': 2, 'name': 'Second package', 'products': [
        {'id': 2, 'name': 'first product', 'active': True},
        {'id': 3, 'name': 'third product', 'active': True},
    ]},
    {'id': 3, 'name': 'Third package', 'products': []}

]

I thought about creating a list of dictionaries from Packages by .values(), then iterate it and exclude all not active products. Do you know any more elegant way to do it?

Upvotes: 0

Views: 104

Answers (2)

grouchoboy
grouchoboy

Reputation: 1024

I'm not sure if this will work. But I think that we can play using the serializers.MethodSerialier. If it fails probably we can try to return another thing instead of the Productserializer directly.

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ('id', 'name')


class PackageSerializer(serializers.ModelSerializer):
    products = serializers.MethodSerializer()

    class Meta:
        model = Package
        fields = ('id', 'name', 'products')

    def get_products(self, obj):
        products = obj.products.filter(active=True)
        return ProductSerializer(products, many=True)


packages = Package.objects.filter(products__active=True)
serializer = PackageSerializer(packages, many=True)
# do something with the serializer

Upvotes: 1

JPG
JPG

Reputation: 88479

AFAIK, you won't get a nested output from Django :( But you will get something similar with .values() method of QuerySet class as,

results = Package.objects.filter(products__active=True).values('id', 'name', 'products__id', 'products__name', 'products__active')
filtered_result = [result for result in results if result['products__active']]

Upvotes: 1

Related Questions