Accessing the attribute of a model through a shared foreign key in another model

I am a complete newbie to the world of Django and I'm confused as to how I can access the list of values from a table that has access to another table through a foreign key.

Here is the Request model:

class Request(models.Model):
    """
    Carry requests
    """

    sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="requests")
    offers = models.ManyToManyField("Offer", blank=True)
    code = models.UUIDField(max_length=64, default=uuid.uuid4, editable=False)
    weight = MeasurementField(
        measurement=Weight, validators=[MinValueValidator(Weight(g=1))], verbose_name=gettext_lazy("Weight")
    )
    description = models.TextField(blank=False)
    origin_country = models.ForeignKey(
        Country, on_delete=models.PROTECT, related_name="origin_requests", verbose_name=gettext_lazy("Origin Country")
    )
    origin_city = models.ForeignKey(
        City, on_delete=models.PROTECT, related_name="origin_requests", verbose_name=gettext_lazy("Origin City")
    )
    destination_country = models.ForeignKey(
        Country,
        on_delete=models.PROTECT,
        related_name="destination_requests",
        verbose_name=gettext_lazy("Destination Country"),
    )
    destination_city = models.ForeignKey(
        City,
        on_delete=models.PROTECT,
        related_name="destination_requests",
        verbose_name=gettext_lazy("Destination City"),
    )
    status = models.CharField(max_length=40, choices=Status.choices, default=Status.AVAILABLE)
    reward = MoneyField(
        max_digits=1000,
        decimal_places=2,
        default_currency="PHP",
        validators=[MinMoneyValidator(defaultdict(lambda: 0.01))],
        verbose_name=gettext_lazy("My Initial Offer Fee"),
    )
    photo = models.ImageField(upload_to="requests/", verbose_name=gettext_lazy("Photo of Item"))
    accepted_offer = models.ForeignKey(
        "Offer", on_delete=models.SET_NULL, blank=True, null=True, related_name="accepted_requests"
    )
    add_insurance = models.BooleanField(default=False, verbose_name=gettext_lazy("I WANT 100% INSURANCE FOR MY ITEMS"))
    declared_amount = MoneyField(
        max_digits=1000,
        decimal_places=2,
        default_currency="PHP",
        validators=[MinMoneyValidator(defaultdict(lambda: 0.01))],
        verbose_name=gettext_lazy("Declared Amount"),
        blank=True,
        null=True,
    )
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    history = HistoricalRecords(excluded_fields=["sender", "code", "created", "modified"])

    @property
    def short_code(self) -> str:
        return str(self.code)[:8]

    def __str__(self) -> str:
        return f"({str(self.code)[:8]}) @{self.sender.username}: {self.origin_country} -> {self.destination_country}"

Here is the Negotiation model:

class Negotiation(models.Model):
    request = models.ForeignKey("Request", on_delete=models.CASCADE, related_name="negotiations")
    offer = models.ForeignKey("Offer", on_delete=models.CASCADE, related_name="negotiations")
    price = MoneyField(
        max_digits=1000,
        decimal_places=2,
        default_currency="PHP",
        validators=[MinMoneyValidator(defaultdict(lambda: 0.01))],
        verbose_name=gettext_lazy("Offered Price"),
        default=Money(amount=0.00, currency="USD"),
    )
    status = models.CharField(max_length=40, choices=NegotiationStatus.choices, default=NegotiationStatus.NEGOTIATING)
    reported_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        related_name="reported_negotiations",
    )
    report_description = models.TextField(blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = [["request", "offer"]]

    def __str__(self) -> str:
        return f"Negotiation: {str(self.request)} <-> {str(self.offer)}"

views.py:

class NegotiationsView(TemplateView):
    template_name = "expadite/negotiations.html"
    extra_context = {"page": "negotiations"}

    def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> TemplateResponse:
        if kwargs.get("tab") not in (None, "travellers", "senders"):
            return redirect(to=reverse("expadite:negotiations/tab", kwargs={"tab": "travellers"}))
        return super(NegotiationsView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs: Any) -> Dict:
        context = super(NegotiationsView, self).get_context_data(**kwargs)
        context.update({"tab": kwargs.get("tab", "travellers")})
        return context

Basically, if I want to, say, get the origin_country of requests that are in negotiation, how do I do it?

Somewhere in your get(), you're going to want to find all the negotiations. From the docs:

negotiations = Negotiation.objects.all()

You may optionally want to filter them:

negotiations = Negotiation.objects.filter(status=...)

Then you want to iterate over each negotiation and use . to access the request and again to access the origin

for negotiation in negotiations:
    print(negotiation.request.origin_country)
Back to Top