Django Queryset по нескольким внешним ключам

I am struggling with building a QuerySet to get all objects belonging to the current logged-in user. The bills are assigned to a Customer, and CustomerUser objects are assigned to the Customer:

  ┌──────┐      ┌──────────┐
  │ Bill │ ───► │ Customer │
  └──────┘  FK  └──────────┘
                     ▲
                     │
                     │ FK

            ┌──────────────┐
            │ CustomerUser │
            └──────────────┘

                     │
                     │ FK
                     ▼
┌──────────────────────────┐
│ contrib.auth.models.User │
└──────────────────────────┘

Модели:

class Bill(models.Model):
    date = models.DateField(blank=False)
    total = models.FloatField(blank=False, null=False, default=0.0)
    customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)

class Customer(models.Model):
    name = models.CharField(max_length=25, blank=False, null=False)

class CustomerUser(models.Model):
    first_name = models.CharField(max_length=30, blank=True, null=True)
    last_name = models.CharField(max_length=30, blank=True, null=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)

Basically I want to craft a QuerySet that returns the Bill objects the CustomerUser has access to. Can this be done with a single QuerySet?

Сначала включите внешний ключ в модель customer с именем поля 'custom_user', связывающий с моделью customuser

class Customer(models.Model):
name = models.CharField(max_length=25, blank=False, null=False)
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True, null=True)

и затем вы можете использовать запрос как

Bill.objects.filter(customer__custom_user__user_id=logged_in_user_id)

Вы забыли включить один fk между CustomerUser и Customer, поэтому я сделал некоторые предположения, но что-то вроде этого должно работать. В основном вам нужно соединить ваши модели с помощью сериализаторов и передать соответствующие related_name.

# serializers

class BillSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bill
        fields = ('id',)


class CustomerSerializer(serializers.ModelSerializer):
    bills = BillSerializer(read_only=True, many=True, source='bill_set')
    
    class Meta:
        model = Customer
        fields = ('id', 'bills')


class CustomerUserSerializer(serializers.ModelSerializer):
    customer = CustomerSerializer(read_only=True)

    class Meta:
        model = CustomerUser
        fields = ('id', 'customer')


class UserSerializer(serializers.ModelSerializer):
    customer_users = CustomerUserSerializer(many=True, read_only=True, source='customer_user_set')

    class Meta:
        model = User
        fields = ('customer_users',)

# viewset

class UserViewSet(mixins.RetrieveModelMixin, GenericViewSet):
    serializer_class = UserSerializer
    
    def get_queryset(self):
        user = self.request.user
        queryset = super().get_queryset()
        queryset = queryset.filter(pk=user.pk)
        return queryset

Помните о предварительной выборке всего, что вам нужно, потому что этот select может быть довольно тяжелым.

Вернуться на верх