# Views and URLs — Django / FastAPI

Source: https://www.skillbyai.com/en/django-fastapi/v-views

> Function views returning JSON.

## urls.py routes to views

A **view** receives an HttpRequest and returns an HttpResponse; `JsonResponse` serialises dictionaries for APIs. **URL patterns** map paths (with converters such as `<int:pk>`) to views and get names for `reverse()`. Helpers like `get_object_or_404` and decorators like `require_GET` reduce boilerplate. For larger APIs, Django REST Framework or Django Ninja add serializers, validation, authentication and OpenAPI docs.

## Requests in, validated data out

Views and URLs serve requests, forms validate input, and transactions keep data consistent.

![Three ideas: views and URLs, forms, transactions and protection.](assets/figures/django-fastapi/section-6-map.svg) — Figure 6.1 — Views, forms and transactions.

## The catalog views and URLs

I ran this with Django 6.1.1 and Python 3.12 in a demo project (shopsite with a catalog app) using SQLite. A filtered list view using select_related and a detail view returning 404 for missing products; URL names are used by the tests.

```python
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_GET

from .models import Product


@require_GET
def product_list(request):
    max_price = request.GET.get("max_price")
    qs = Product.objects.select_related("category").filter(in_stock=True)
    if max_price:
        qs = qs.filter(price__lte=max_price)
    data = [{"name": p.name, "price": str(p.price), "category": p.category.name} for p in qs]
    return JsonResponse({"count": len(data), "results": data})


@require_GET
def product_detail(request, pk):
    p = get_object_or_404(Product, pk=pk)
    return JsonResponse({"id": p.pk, "name": p.name, "price": str(p.price)})

# catalog/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("products/", views.product_list, name="product-list"),
    path("products/<int:pk>/", views.product_detail, name="product-detail"),
]
```

## Name every URL

Named URLs let code and tests use reverse() instead of hard-coded paths.

**Quiz:** What does get_object_or_404 do when the object is missing?

- [x] Raises Http404, producing a 404 response
- [ ] Returns None
- [ ] Creates the object
- [ ] Returns status 500

*Answer:* Raises Http404, producing a 404 response. Clean not-found handling.
