Feature: Unified Image Storage using InvenTreeImage Model
This pull request introduces a major refactoring of the image management system, transitioning from a distributed approach to a unified, single-table architecture. By centralizing image storage into a new InvenTreeImage model, this change simplifies the database schema, reduces data duplication, and provides a more robust and extensible foundation for handling images across the application.
This work is a continuation of the efforts and discussions from the previous pull request (#10069)
Key Architectural Changes & Features
- Unified
InvenTreeImageModel: All uploaded images are now stored in a singleInvenTreeImagetable (previously namedUploadedImage). This model uses a Generic Foreign Key to associate images with various other models (e.g.,Part,Company), making the system highly extensible for future use cases and plugins. - Duplicate Prevention: A
sha256hash is now calculated and stored for each uploaded image. The system uses this hash to prevent identical images from being stored multiple times, saving significant storage space. - Modernized Path Handling: All file path operations have been updated from
os.pathtopathlib.Pathfor improved cross-platform compatibility and code readability. - Automatic Cleanup: A custom
CustomStdImageFieldhas been implemented, which automatically deletes image files from the storage when the corresponding database record is removed, preventing orphaned files. - Reusable Serialization: A new
InvenTreeImageSerializerMixinprovidesimage_urlandthumbnail_urlfields, ensuring consistent and efficient image serialization across different API endpoints while mitigating N+1 query problems.
Tasks Completed
- [x] Created a new, unified table for all images (
InvenTreeImage). - [x] Implemented a robust data migration script to move all existing
PartandCompanyimages to the new table. - [x] Removed old, redundant image tables after successful migration.
- [x] Implemented a mixin-style architecture using Generic Foreign Keys for associating images with other models.
- [x] Exposed the new
InvenTreeImagemodel through a dedicated API namespace. - [x] Restored and improved previous image functionalities (e.g., thumbnails) in the new model.
- [x] Updated the Part and Company UI to use the new image management system, including an image carousel for multiple images.
- [x] Resolved all merge conflicts with the
masterbranch. - [x] Added comprehensive unit tests for the new API, including tests for image migration (
TestLegacyImageMigration). - [x] Optimized all new and modified API endpoints to prevent N+1 query issues.
- [x] Updated the script for creating the test database.
- [ ] Update test database creation script
New API Endpoints
A new API namespace for images has been introduced:
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/image/ |
List all images |
POST |
/api/image/ |
Upload a new image |
GET |
/api/image/<pk>/ |
Retrieve a specific image |
PATCH |
/api/image/<pk>/ |
Update a specific image |
DELETE |
/api/image/<pk>/ |
Delete a specific image |
GET |
/api/image/thumbs/ |
Retrieve image thumbnails |
Addressing Previous Feedback
Based on the review of PR #10069, the following changes were made:
- Model Naming:
UploadedImagewas renamed toInvenTreeImagefor clarity. - Generic Relations: The association mechanism was rebuilt using
GenericForeignKeyinstead of a custom implementation, improving integration possibilities for plugins. - API Consistency: Thumbnail URLs are now exposed directly via the serializers, maintaining consistency with previous API behavior and avoiding breaking changes where possible.
- Code Cleanup: All commented-out code has been removed in favor of clean, intentional changes.
- Test Structure: Generic tests for the
InvenTreeImagemodel are now located incommon/, while model-specific tests (e.g., forPart) remain in their respective app directories.
This PR is now complete, with all tests passing and functionality fully implemented. It is ready for a final review.
Related Issues
Closes #9788 Supersedes #10069
Deploy Preview for inventree-web-pui-preview ready!
| Name | Link |
|---|---|
| Latest commit | 329ded93ba8303ca53778bd41b0c3f80e366ca11 |
| Latest deploy log | https://app.netlify.com/projects/inventree-web-pui-preview/deploys/6910ee754e2384000834f4b0 |
| Deploy Preview | https://deploy-preview-10484--inventree-web-pui-preview.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
Lighthouse |
1 paths audited Performance: 93 (🔴 down 2 from production) Accessibility: 81 (no change from production) Best Practices: 100 (no change from production) SEO: 78 (no change from production) PWA: - View the detailed breakdown and full score reports |
To edit notification comments on pull requests, go to your Netlify project configuration.
Codecov Report
:x: Patch coverage is 95.86984% with 33 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 88.09%. Comparing base (726e852) to head (329ded9).
Additional details and impacted files
@@ Coverage Diff @@
## master #10484 +/- ##
==========================================
+ Coverage 87.92% 88.09% +0.16%
==========================================
Files 1278 1286 +8
Lines 57447 58045 +598
Branches 2005 1993 -12
==========================================
+ Hits 50512 51133 +621
+ Misses 6437 6416 -21
+ Partials 498 496 -2
| Flag | Coverage Δ | |
|---|---|---|
| backend | 89.32% <74.21%> (-0.22%) |
:arrow_down: |
| migrations | 42.72% <56.44%> (+0.28%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
| Components | Coverage Δ | |
|---|---|---|
| Backend Apps | 91.99% <100.00%> (+0.05%) |
:arrow_up: |
| Backend General | 93.94% <95.64%> (+0.27%) |
:arrow_up: |
| Frontend | 70.50% <ø> (+0.09%) |
:arrow_up: |
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@Reza98Sh some CI tests are not passing, please address that before we start reviews
Could we change the API references from thumbnail_url to thumbnail and image_url to image? That would reduce the breaking changes in the API
Could we change the API references from
thumbnail_urltothumbnailandimage_urltoimage? That would reduce the breaking changes in the API
for part that have multiple images
"images": [
{
"pk": 0,
"primary": true,
"image": "http://example.com/",
"thumbnail": "string"
}
],
"image_url": "string",
"thumbnail_url": "string",
but for company image that only have one image:
"image": {
"pk": 1,
"primary": true,
"image": "/media/images/company_3_img_OAbJ7MY.jpg",
"thumbnail": "/media/images/company_3_img_OAbJ7MY.thumbnail.jpg"
},
"image_url": "string",
"thumbnail_url": "string",
What do you think about this change?
Maybe I have not communicated the goal good enough: current users of the API have request with the fields thumbnail and image - with this change they will have to change their calls to thumbnail_url and image_url. Why do we need to break the API for those users?
I noticed the confusion came from turning image and thumbnail from simple URL fields into objects after moving images to a separate table.
To avoid naming conflicts and keep the API backward-compatible, I’ll remove the embedded image object from Part and Company serializers. Instead, these endpoints will once again return image and thumbnail as URL fields — just like before.
They will again return image and thumbnail as URLs, while detailed image data can be fetched from the new /api/image/ endpoint.
You can extend the fields as much as you want, but renaming old fields without a good reason is an issue.
@Reza98Sh are you ok with me implementing some of the open comments? Would like to get this over the line
I’ve been quite busy over the past couple of weeks.
I’ve reviewed the context, and your review makes perfect sense. I will work on implementing these changes and plan to push the new code within the next few days.
Thanks you!
@matmair Excuse me. Should I also add unit test in the front end ? Could you give me a few hint how do I write test in front end?
I’ve added several tests for the migrations. However, the code coverage report is flagging the test file itself (src/backend/InvenTree/common/test_migrations.py) for low coverage ! I don't know how I can increase code coverage
@Reza98Sh touching up areas of the frontend that are changed without coverage would be great. We use Playwright for frontend tests, the framework has a pretty great vscode extension that I would recommend and is well-supported by copilot and other AI agents if you run into issues. The tests are in src/frontend/tests
Some test are not passing, which is why the files are getting flagged; solving the test not passing should adress the code coverage issues or make them much less significant
Most of the failing test seem to related to the renaming / removal / change of default behavior (None if nothing is set, not a blank image reference) on the image and thumbnail fields; which is what I was warning about above
we can either change the name in the tests or of the fields to address that
@matmair
I’ve fixed the failed tests related to the database. Now I need some help with the remaining CI failures.
Could you guide me on how to pass these tests?
QC / Style [Typecheck] QC / Tests - API Schema Documentation QC / Tests - inventree-python
I couldn't find test files related to QC / Tests - inventree-python
Typecheck and API Schema Documentation can be ignored - the first was an issue with external infra; the API docs passed but the change is so large that it times out
inventree-python is an integration test against https://github.com/inventree/inventree-python
If these tests fail it is highly preferable to fix the API behavior instead of the tests. Consumers will not update their client version immediately
The response schema for the part and company list/detail endpoint remains unchanged. However, for adding and deleting images for parts, the old API approach can no longer be used because it may have multiple images.
What is your suggestion?
@matmair @SchrodingersGat I think it’s ready for the next round of review
If it needs further changes or refinement, please feel free to let me know.
@Reza98Sh apologies, have been very busy and not had a chance to review this yet. It's on my list
@Reza98Sh if you can fix conflicts here, I'll pull down the code and do a proper operational review, but overall your approach looks good here.
Note that the recent updates to make parameters generic - https://github.com/inventree/InvenTree/pull/10699 - have introduced some very similar refactoring of components, so there may need to be some slight tweaks to bring your code in line with the recently merged PR.
@SchrodingersGat Thanks regarding the review. I’m a bit busy at the moment, but I will get back to this and fix the conflicts as soon as possible.
