Django related_name not querying the data in template

Viewed 1030

I have two models, Transaction and Subscription. Transaction has a FK to Subscription with the related name="subscription_transaction". I am trying to query the transaction.amount on a SubscriptionDetailView. Why is my template query not working.

Neither work

subscription_detail.html

<td  class="text-dark ">{{ subscription.subscription_transaction.timestamp.all }}</td
<td  class="text-dark"> {{ subscription.subscription_transaction.amount }}</td>`

models.py

class Subscription(models.Model):
    id = models.CharField(max_length=36, unique=True, default=uuid.uuid4, primary_key=True, editable=False)
    user_membership = models.ForeignKey(UserMembership, on_delete=models.CASCADE)
    stripe_subscription_id = models.CharField(max_length=40)
    active = models.BooleanField(default=True)

    def __str__(self):
        return self.user_membership.user.username

    @property
    def get_created_date(self):
        subscription = stripe.Subscription.retrieve(self.stripe_subscription_id)
        return datetime.fromtimestamp(subscription.created)

    @property
    def get_next_billing_date(self):
        subscription = stripe.Subscription.retrieve(self.stripe_subscription_id)
        return datetime.fromtimestamp(subscription.current_period_end)


class Transaction(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="user_transaction")
    order_id = models.CharField(max_length=36, unique=True, default=uuid.uuid4, primary_key=True, editable=False)
    subscription = models.ForeignKey(Subscription, on_delete=models.SET_NULL, null=True, blank=True, related_name="subscription_transaction")
    amount = models.DecimalField(max_digits=100, decimal_places=2)
    success = models.BooleanField(default=True)
    timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
2 Answers

Since subscription.subscription_transaction is a RelatedManager object, you can get all transactions of the subscription using .all.

Example:

{% for transaction in subscription.subscription_transaction.all %}
    Timestamp: {{ transaction.timestamp }}, 
    Amount: {{ transaction.amount }}
{% endfor %}

Notice that Transaction has a ForeignKey to Subscription. That's a one to many relation: Each Transaction row can have up to one Subscription however each Subscription can be related with many Transactions.

Following this you should now understand that you are able to use the direct relation betwen Transaction and Subscription (i.e from a Transaction instance) directly, i.e you can do something like transaction.subscription.active sincec each transaction will have one subscription. However, to use the reverse relation (i.e from Subscription) you need to properly use the related object manager to enumerate all possible transactions the subscription may have. Remember that Django auto-names the reverse relation object something_set (in your case instead of subscription_transaction you'd have a transaction_set attribute to the Subscription instance); there's a reason for that: To remember that the reverse relation of a foreign key is a set of objects!

Thus, if you change your template code to something like:

{% for tr in subscription.subscription_transaction.all %}
  {{ tr.timestamp }}
  {{ tr.amount }}
{% endfor %}

it will output all the transactions of the subscription.

Related