Use model data in model form with update view

I have a model for transactions:

class Transaction(models.Model): 
    id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
    transaction_date = models.DateField(null=False, blank=False)
    transaction_category = models.ForeignKey(Category, on_delete=models.PROTECT, null=False, blank=False)
    customer_vendor = models.ForeignKey(CustomerVendor, on_delete=models.PROTECT, blank=False, null=False) # where did you get this money or spend this money
    account = models.ForeignKey(Account, on_delete=models.PROTECT, blank=False, null=False)
    tag = models.ManyToManyField(Tag, blank=True)
    amount = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
    description = models.CharField(max_length=255, null=False, blank=False)

The transaction model references the Tag model (many to many relationship):

class Tag(models.Model):
    id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
    tag_name = models.CharField(null=False, blank=False, max_length=255, unique=True)
    tag_description = models.TextField(null=True, blank=True)
    active = models.BooleanField(default=True)

The Tag model has a field called “Active”, which is a boolean. If a Tag is no longer actively being used, that can be turned to False.

In the Transaction model form, I have a query that only displays active tags.

class TransactionForm(ModelForm):
    tag = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(active=True).order_by('tag_name'), required=False, widget=forms.SelectMultiple(attrs={'class': 'mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50'}))

The issue is that if a tag has the “Active” field marked as False after it has been used in a transaction, it will not show up in the form when doing an update. Then if you update and save the transaction, it looses any tags that are not currently marked as Active.

My Question: How do I query tags that are used in a transaction but are not active when doing an update using the model form.

I am thinking something like this:

tag = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(Q(active=True) | Q()).order_by('tag_name')

But I am not sure what to put in the second Q to get any tags that are already apart of the transaction that are not active.

Any help much appreciated!

For clarity, are you talking about tags currently referenced by any Transaction, or are you just looking for the tags currently selected by the current Transaction instance? (You’ve identified this as an update view, which means there would be a current existing Transaction instance.)

If the latter, I don’t think you’re going to be able to do it from within the field definition. I believe this would be a queryset needing to be executed from within the __init__ method of the form, such that you have the instance of the model available.

And in that case, assuming that this is a model form with Transaction as the affected model, I’m expecting you can do something like this:

def __init__(...):
    super().__init__(...)
    ...
    self.fields['tag'].queryset = 
        Tag.objects.filter(
            Q(active=True) |
            Q(transaction=self.instance)
        )
    ...

(I’m winging this - there may be an error or ten in here, but should give you an idea of a starting point)

1 Like

Wow, did not know you could do that. Thank you!