1

I need the following URLs to work where ticker would stand for a stock ticker such as AAPL or AMZN, and is stands for income_statement.

localhost:8000/stocks/ localhost:8000/stocks/<TICKER>/ localhost:8000/stocks/<TICKER>/is/

in the views.py file below I am using a viewset which and router which automatically configures the first two urls above, and for the third url I am using the action decorator with methods=['get'] and url_path="is" to achieve the localhost:8000/stocks/<TICKER>/is/ path.

the third URL is configured, but I get a key error for ticker when entering the following url in the browser: localhost:8000/stocks/AAPL/is/

what am I doing wrong here, I believe the error is in the views.py get_income_statement function?

models.py

class Stock(models.Model):

    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    ticker = models.CharField(max_length=10, unique=True, primary_key=True)
    slug = models.SlugField(default="", editable=False)

    def save(self, *args, **kwargs):
        value = self.ticker
        self.slug = slugify(value, allow_unicode=True)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.ticker

    class Meta:
        verbose_name = "stock"
        verbose_name_plural = "stocks"
        ordering = ["ticker"]

class IncomeStatement(models.Model):
    ticker = models.ForeignKey(
        Stock, on_delete=models.CASCADE, related_name="income_statements"
    )

    date = models.DateField(default=datetime.date.today)
    PERIODICITY_CHOICES = [("ANNUAL", "ANNUAL"), ("QUARTERLY", "QUARTERLY")]
    periodicity = models.CharField(
        max_length=10, choices=PERIODICITY_CHOICES, default="annually"
    )
    net_income_continuous_operations = models.DecimalField(
        max_digits=20, decimal_places=2

views.py

class StockViewSet(viewsets.ModelViewSet):
    queryset = Stock.objects.all()
    serializer_class = StockSerializer
    # lookup_field = "slug"

    @action(detail=True, methods=["get"], url_path="is", url_name="is")
    def get_income_statement(self, request, *args, **kwargs):
        income_statement = self.queryset.get(ticker=kwargs["ticker"]).select_related(
            "income_statements"
        )
        serializer = IncomeStatementSerializer(data=income_statement)
        if serializer.is_valid():
            return Response(serializer.data)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

urls.py

router = DefaultRouter()
router.register(r"stocks", views.StockViewSet)
urlpatterns = router.urls
Aran Freel
  • 3,085
  • 5
  • 29
  • 42

1 Answers1

3

Set lookup_field = "ticker"

class StockViewSet(viewsets.ModelViewSet):
    # rest of your code
    lookup_field = "ticker"

Update-1

class StockViewSet(viewsets.ModelViewSet):
    queryset = Stock.objects.all()
    serializer_class = StockSerializer
    lookup_field = "ticker"

    @action(detail=True, methods=["get"], url_path="is", url_name="is")
    def get_income_statement(self, request, *args, **kwargs):
        is_qs = IncomeStatement.objects.filter(ticker=self.get_object())
        serializer = IncomeStatementSerializer(is_qs, many=True)
        return Response(serializer.data)
JPG
  • 82,442
  • 19
  • 127
  • 206
  • that fixed the original problem, now I get the error `'Stock' object has no attribute 'select_related'` – Aran Freel Aug 20 '20 at 12:30
  • 2
    `select_related` will only work with *QuerySet* not objects – JPG Aug 20 '20 at 12:31
  • 1
    Also, I don't see any reason that you need to call the `select_related()` – JPG Aug 20 '20 at 12:33
  • how would you do it ? – Aran Freel Aug 20 '20 at 12:36
  • I used `model_to_dict` wrapper from django and now I have all the fields with the error `this field is required` – Aran Freel Aug 20 '20 at 12:40
  • I think there is an error in `self.get_object` I returned the error `ot AttributeError when attempting to get a value for field `net_income_continuous_operations` on serializer `IncomeStatementSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Stock` instance. Original exception text was: 'Stock' object has no attribute 'net_income_continuous_operations'.` I believe this is because I need to go one level deeper to the income_statements foreign key – Aran Freel Aug 20 '20 at 12:48
  • 1
    That error indicates that you have defined one (or more fields) incorrectly. – JPG Aug 20 '20 at 12:49
  • is it possible since I want to return more than one income statement that its not serializing the list of income statements correctly, because the other two urls are working fine – Aran Freel Aug 20 '20 at 12:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220143/discussion-between-aran-freel-and-arakkal-abu). – Aran Freel Aug 20 '20 at 12:58
  • can you explain to me how *args and **kwargs makes this snippet work . . . I don't get what it is providing to the function that makes it work – Aran Freel Aug 20 '20 at 13:14
  • 1
    url parameters are passed to `kwargs` – JPG Aug 20 '20 at 13:17
  • so url parameters being ticker or is in the snippet above ? – Aran Freel Aug 20 '20 at 18:55
  • how to make the urls in this case insensitve so whether the stock name is AAPL or aapl or Aapl in the URL it won't matter – Aran Freel Aug 21 '20 at 08:45
  • Please ask a new question – JPG Aug 21 '20 at 08:47