Building a Resume Management API in Django: Validation, Storage, and Cleanup
Today I completed another important milestone in my Placement Portal: the core Resume Management APIs.
Students can now upload, list, and delete their resumes through dedicated APIs. While these endpoints sound straightforward, building them involved much more than implementing basic CRUD operations.
The real challenge was designing the complete lifecycle of a resume—from validation to storage and finally cleanup.
Listing Student Resumes
The listing API follows the same authorization pattern used throughout the project.
Instead of accepting a student identifier from the client, the authenticated user is obtained from the request, and the corresponding student profile is resolved on the backend.
Using that profile, the queryset is filtered so that students can only access resumes they own.
Each response includes:
- Student reference
- File name
- File size
- Uploaded PDF
This keeps the API secure while ensuring every student only sees their own documents.
Simplifying Resume Upload
Although a resume record contains multiple fields, the client only needs to upload one thing:
- The PDF file
Everything else is derived automatically.
The serializer receives the uploaded file along with the authenticated request through its context.
Before saving, the API performs validation to ensure:
- The uploaded document is a PDF.
- The file size stays within the configured upload limit.
Once validation succeeds, the serializer extracts useful metadata such as the file name and file size before creating the database record.
At the same time, Django stores the uploaded document inside the configured media directory.
This keeps metadata in the database while storing the actual file separately on disk.
Preventing Orphaned Files
Deleting uploaded files is often overlooked.
Removing only the database record leaves unused files occupying storage.
To prevent this, I customized the deletion workflow.
When a delete request is received:
- The resume is located using both the primary key and the authenticated student.
- The custom model
delete()method removes the physical file from storage. - The database record is then deleted.
This ensures the database and the file system always remain synchronized.
Why This Matters
File uploads are different from ordinary database records.
Every uploaded document creates two pieces of data:
- A database entry.
- A physical file.
Managing only one of them eventually leads to inconsistencies or wasted storage.
By validating uploads, automatically extracting metadata, restricting access to authenticated users, and cleaning up files during deletion, the Resume Management module now provides a complete document lifecycle.
What's Next?
The next step is integrating these APIs with the application workflow.
Instead of uploading a resume every time they apply, students will be able to choose one of their existing resumes or upload a new one during the application process.
That small improvement will make applying for jobs much faster while avoiding unnecessary duplicate uploads.
Final Thoughts
One thing this feature reinforced is that file management isn't just about storing documents.
It's about designing a reliable lifecycle—validation, persistence, authorization, retrieval, and cleanup.
Getting those details right early makes the system easier to maintain as it grows.
I'm documenting every engineering decision while building this Placement Portal in public.