Brian
Brian

Reputation: 25

Exclude a QuerySet from a pre-existing filtered QuerySet based on a One-to-One relationship

I have a Django application with three models:

class Strategy(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    ...

class Version(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    strategy = models.ForeignKey(Strategy, on_delete=models.CASCADE)
    ...

class Tool(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    version = models.OneToOneField(Version, on_delete=models.CASCADE)
    ...

On the Tool model's corresponding ToolForm, I filter the QuerySet for the 'version' field, so that the User only sees the strategy versions they submitted:

def __init__(self, user, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields['version'].queryset = Version.objects.filter(strategy__user=user.id)

I now want to filter this QuerySet further to exclude Versions which already have Tools. The Version to Tool relationship is One-to-One, and I only want the User to see Versions which still require Tools to be submitted. I have tried numerous approaches, but I keep coming back to versions of:

Version.objects.filter(strategy__user=user.id).exclude(Tool.objects.filter(version__strategy__user=user.id).values('version_id'))

Version.objects.filter(strategy__user=user.id).exclude(Tool.objects.filter(version__strategy__user=user.id).values_list('version_id'))

Both "exclude" queries return the One-to-One field 'version_id' for the Tool entries. Respectively, the responses I get are:

'dict' object has no attribute 'split'
'tuple' object has no attribute 'split'

What am I missing? How can I exclude Versions from my ToolForm 'version' field that already have the One-to-One relationship established?

Upvotes: 1

Views: 83

Answers (1)

ruddra
ruddra

Reputation: 51988

You do not need exclude here. You can simply use tool__isnull=True:

Version.objects.filter(strategy__user=user.id, tool__isnull=True)

Due to OneToOne relation between Version and Tool instances, Version has a field named tool(all lowercase model name unless you defined related_name). For Version instances which does not have Tool, the field will be empty. So isnull=True will check for Version instances which does not have any tool.

Upvotes: 1

Related Questions