How to generate a Postman collection from Django REST framework
Step-by-step: turn a Django REST framework API into a ready-to-use Postman collection with bodies, JWT login and environments, without drf-spectacular or drf-yasg.
If you build APIs with Django REST framework, you've probably made a Postman collection by hand: copying URLs from urls.py, guessing the JSON a serializer wants, pasting a token into every request. It's slow, and it's out of date by the next sprint.
This guide shows how to generate the whole collection from your DRF code with routeman, a free CLI, in a couple of minutes. You don't need drf-spectacular, drf-yasg or any OpenAPI setup.
What you'll end up with
- A folder per Django app, with every router, ViewSet action and APIView endpoint.
- Request bodies built from your serializers, with example values that pass validation (choices, max lengths, numeric ranges).
- A login request that saves
access_tokenandrefresh_token, so every other request is authenticated automatically. - Pagination, search, ordering and django-filter query parameters, added but disabled until you need them.
- A Postman environment per server (local, staging, production).
Step 1: install routeman in your project's virtualenv
routeman imports your Django project to read the URLconf, so install it where Django and DRF are already installed:
$ source .venv/bin/activate
$ pip install routeman
$ routeman --version
routeman 0.1.0
It has no dependencies of its own, so it won't conflict with your project's packages.
Step 2: preview the routes
From the folder containing manage.py, list what routeman finds. Here's the real output for a small shop API with a ProductViewSet registered on a DefaultRouter and SimpleJWT views:
$ routeman routes
GET /api/v1/ ๐
POST /api/v1/auth/token/ json: username, password
POST /api/v1/auth/token/refresh/ json: refresh
GET /api/v1/products/ ๐
POST /api/v1/products/ ๐ form: name, sku, price, status, image
DELETE /api/v1/products/{pk}/ ๐
GET /api/v1/products/{pk}/ ๐
PATCH /api/v1/products/{pk}/ ๐ form: name, sku, price, status, image
PUT /api/v1/products/{pk}/ ๐ form: name, sku, price, status, image
POST /api/v1/products/{pk}/publish/ ๐ form: name, sku, price, status, image
10 routes, auth: bearer
Notice a few things. The custom @action (publish) is there. The product endpoints use form (multipart) because the serializer has an ImageField. The Django admin isn't listed. A lock marks every endpoint that needs a token, based on DEFAULT_PERMISSION_CLASSES.
Step 3: generate the collection
$ routeman generate
โ django: 10 requests (4 POST, 3 GET, 1 PUT, 1 PATCH, 1 DELETE)
โ auth: bearer (login: POST /api/v1/auth/token/)
โ wrote postman/shop-api.postman_collection.json
โ wrote postman/shop-api.local.postman_environment.json
done in 0.26s - import the files in Postman (File โ Import)
routeman found SimpleJWT's JWTAuthentication in REST_FRAMEWORK settings and picked TokenObtainPairView as the login request without being told.
Step 4: import into Postman and log in
- In Postman, choose File โ Import and drop both files from
postman/. - Select the Shop API - local environment in the top-right corner.
- Fill in
usernameandpasswordin the environment. - Open Auth โบ Token obtain pair and click Send.
The login request's test script finds access and refresh in the response and saves them as access_token and refresh_token. The collection uses Bearer {{access_token}}, so every request under Shop is now authenticated. When the token expires, send Token refresh. Its body is already {"refresh": "{{refresh_token}}"}.
What the generated requests look like
Create product is a multipart request with these fields:
| Key | Type | Value | Why |
|---|---|---|---|
name | text | John Doe | Field-name aware example |
sku | text | string | Plain CharField |
price | text | 1.5 | DecimalField |
status | text | draft | First valid choices value |
image | file | (file picker) | ImageField |
The read-only id is left out. List products has page, search and ordering query parameters, disabled by default, because the view uses PageNumberPagination, SearchFilter and OrderingFilter. Detail routes use {{product_id}}, named after the model rather than the raw pk.
Token auth, Knox and session auth
JWT isn't required. If your project uses rest_framework.authtoken or Knox, routeman sends Authorization: Token {{access_token}} and stores the token from the login response. Projects that need a custom prefix (for example JWT) can set it in routeman.toml:
[routeman.auth]
type = "bearer"
prefix = "JWT"
login = "/api/v1/auth/login/"
Keeping the collection up to date
Run routeman generate again whenever your API changes. Collection and request ids are derived from the project and the route, so re-importing replaces the existing collection in Postman instead of creating "Shop API (1)". Many teams add it to CI and commit the postman/ folder, so reviewers can see API changes in the diff.
Want staging and production environments too?
routeman generate \
-e staging=https://staging.example.com \
-e production=https://api.example.com
Common questions
Do I need to remove drf-spectacular?
No. routeman doesn't use or conflict with it. Keep Swagger UI for public docs if you have it.
My settings read environment variables
Put them in .env next to manage.py (loaded automatically) or pass --env-file. routeman never connects to the database. It only needs settings to import cleanly.
What about views without a serializer?
If an APIView reads request.data.get('email') directly, routeman reads that from the view's source code and adds the field, noting in the request description that the list was inferred.
Next: run the generated collection in CI with Newman, or see the DRF overview.
Try routeman on your project
$ pip install routeman
$ routeman generate