Published at

Adding a `has_rated` Field to Your API Response with Ninja

Adding a `has_rated` Field to Your API Response with Ninja

Learn how to add an additional field to Ninja API responses in Django

Authors
  • avatar
    Name
    James Lau
    Twitter
  • Indie App Developer at Self-employed
Sharing is caring!
Table of Contents

This post explores how to enhance your API responses in a Django application using Ninja, a fast, asynchronous-friendly web framework. We’ll focus on adding a boolean field, has_rated, to indicate whether a user has already rated a particular company associated with a transaction.

Scenario

Imagine you have a system where users can make transactions and then rate the companies involved in those transactions. When a user requests details about a specific transaction, you want to include information about whether they have already rated the company linked to that transaction.

The Code

Here’s the relevant code snippet, broken down for clarity:

try:
    user_transaction = UserTransactions.objects.select_related("company", "user").get(transaction_id=transaction_id)
except UserTransactions.DoesNotExist:
    return JsonResponse({"msg": "transaction does not exist"}, safe=True, status=400)

if user_transaction.user_id != user_id:
    return JsonResponse({"msg": "invalid transaction (not yours)"}, safe=True, status=400)

if hasattr(user_transaction, "company"):
    if user_transaction.company is not None:
        company_id = user_transaction.company.id
        has_rated = BrandRating.objects.filter(user_id=user_id, company_id=company_id).exists()

        user_transaction.has_rated = has_rated

return user_transaction

Explanation

  1. Transaction Retrieval: The code first attempts to retrieve a UserTransactions object based on the provided transaction_id. select_related("company", "user") optimizes the query by fetching related company and user objects in the same database query, preventing multiple database hits (improving performance).
  2. Error Handling: If the transaction doesn’t exist, a JsonResponse with a 400 status code is returned, indicating a bad request.
  3. Authorization Check: It then verifies that the transaction belongs to the requesting user (user_id). If not, another error response is returned.
  4. Company and Rating Check: The core logic resides within the if hasattr(user_transaction, "company") block. This checks if the user_transaction object has a company attribute. Inside this block, it checks if the company is not None. If both conditions are met:
    • The company_id is extracted.
    • A query is performed on the BrandRating model to check if a rating exists for the given user_id and company_id. The .exists() method is used for efficiency; it returns True if any matching records are found, and False otherwise, without fetching the actual rating objects.
    • Finally, the has_rated attribute is dynamically added to the user_transaction object and set to the boolean result of the rating check.
  5. Return Value: The modified user_transaction object, now including the has_rated attribute, is returned.

Integration with Ninja

In a Ninja API, you’d typically serialize the user_transaction object using a Pydantic schema. Make sure your Pydantic schema for UserTransaction includes has_rated: bool as an optional field. This allows Ninja to automatically include the has_rated field in the JSON response.

Benefits

  • Clear API Response: Provides clients with immediate information on whether a user has rated a company, improving user experience.
  • Efficient Database Queries: Uses select_related and exists() for optimized database access.
  • Dynamic Data Enrichment: Demonstrates how to dynamically add information to existing objects before returning them in an API response.

Considerations

  • Performance: For very large datasets, consider caching the rating information to avoid repeated database queries.
  • Data Integrity: Ensure proper indexing on the BrandRating table for user_id and company_id to optimize the rating check query.

By following this pattern, you can effectively enrich your API responses with calculated data, providing more context and value to your API consumers.

Sharing is caring!