Skip to main content
Photos bring your collection to life. FootyCollect provides powerful photo management features including automatic optimization, reordering, captions, and background processing.

Uploading Photos

FootyCollect supports multiple ways to upload photos to your items.

During Item Creation

When adding a new item, you can upload photos directly:
1

Access the Photo Upload Area

In the item creation form, locate the photo upload section. You’ll see a dropzone area for uploading images.
2

Upload Your Photos

Method 1: Click to Browse
  • Click the upload area
  • Select one or multiple image files
  • Supported formats: JPG, PNG, WEBP, and other standard image formats
Method 2: Drag and Drop
  • Drag image files from your computer
  • Drop them onto the upload area
  • Multiple files can be uploaded at once
3

Monitor Upload Progress

Each photo shows:
  • Upload progress bar
  • Thumbnail preview
  • File name and size
Photos are uploaded individually to the server and stored temporarily as orphaned photos until you save the item.
Photos uploaded during creation are associated with your user account but not yet linked to a specific item. When you save the item, they’re automatically associated. If you cancel creation, orphaned photos are cleaned up automatically by a scheduled task.

Adding Photos to Existing Items

You can add more photos to items already in your collection:
  1. Navigate to the item detail page
  2. Click “Add Photos” or “Edit Photos”
  3. Upload using the same drag-and-drop or browse interface
  4. New photos are added with automatic ordering

Photo Limitations

LimitValueNotes
Max Photos Per Item10Configurable via MAX_PHOTOS
Upload Limit (Demo)VariesDemo instances may have storage limits
File SizeNo hard limitLarge files are automatically optimized
Allowed FormatsJPG, PNG, WEBP, etc.Standard image formats
Demo mode enforces upload limits. If you see “Upload limit exceeded” errors, delete some photos to free up space. The error message shows your current usage vs. the limit.

Photo Processing and Optimization

FootyCollect automatically optimizes all uploaded photos for better performance.

Automatic AVIF Conversion

When you upload a photo:
1

Initial Upload

The original image is saved to the item_photos/ directory. The Photo model stores:
  • image - Original uploaded file
  • image_avif - Optimized AVIF version (initially empty)
  • user - Your user ID (for orphan tracking)
  • order - Display order
  • caption - Optional caption
2

Background Processing

A Celery task (process_photo_to_avif) is automatically queued:
process_photo_to_avif.delay(photo.pk)
This task:
  • Runs asynchronously in the background
  • Converts the original image to AVIF format
  • Stores the optimized version in item_photos_avif/
  • AVIF format provides superior compression (smaller files, same quality)
3

Processing Status Tracking

The item’s is_processing_photos flag is set to True while photos are being optimized. You can check processing status via:Endpoint: /collection/items/{item_id}/photos/status/Returns:
{
  "is_processing": true,
  "has_photos": true,
  "photo_count": 5,
  "photos_processing": [123, 124],
  "all_processed": false
}
4

Completion

When all photos are processed:
  • is_processing_photos is set to False
  • The item’s draft status is removed
  • Optimized AVIF images are served to users
  • Original images are kept as fallback
The check_item_photo_processing task runs periodically to ensure all photos are processed. If processing fails, it automatically retries after 5 seconds.

Thumbnail Generation

FootyCollect uses ImageKit to generate thumbnails:
thumbnail = ImageSpecField(
    source='image',
    processors=[ResizeToFill(100, 100)],
    format='JPEG',
    options={'quality': 75}
)
  • Size: 100x100 pixels
  • Format: JPEG
  • Quality: 75% compression
  • Processing: Resize and crop to fill
Thumbnails are generated on-demand and cached for performance.

Reordering Photos

The first photo in your collection is the main image displayed in lists and previews. You can change the order at any time.
1

Access Reorder Interface

On the item detail or edit page, locate the photo management section. Photos are displayed in their current order.
2

Drag to Reorder

Drag and drop photos to rearrange them:
  • Click and hold on a photo
  • Drag it to the new position
  • Drop to set the new order
The interface uses AJAX to save the new order without refreshing the page.
3

Save New Order

The reorder is saved via POST to:
/collection/items/{item_id}/photos/reorder/
With data:
order[]: 456
order[]: 123
order[]: 789
The PhotoService.reorder_photos() method updates the order field for each photo.
Photo reordering is instant. The main photo changes immediately, affecting how your item appears in collection lists and the feed.

Programmatic Reordering

The reorder_photos view accepts an array of photo IDs:
# POST data: order[]=456&order[]=123&order[]=789
new_order = request.POST.getlist('order[]')
photo_orders = [(int(photo_id), index) 
                for index, photo_id in enumerate(new_order)]
photo_service.reorder_photos(item, photo_orders)
Each photo’s order field is updated to match its position in the array.

Adding Captions

Captions help you document specific details about each photo.

How to Add Captions

  1. Navigate to the photo management interface
  2. Click on a photo or its caption field
  3. Enter descriptive text (max 255 characters)
  4. Save to update the photo record

Caption Best Practices

Use captions to note:
  • Photo angles (“Front view”, “Back with nameset”, “Close-up of sponsor”)
  • Condition details (“Minor stain on collar”, “Fading on sleeve”)
  • Special features (“Signed by player”, “Match-worn authentication tag”)
  • Context (“Photo from 2023 match”, “Before cleaning”)

Caption Storage

Captions are stored in the Photo.caption field:
class Photo(models.Model):
    image = models.ImageField(upload_to='item_photos/')
    caption = models.CharField(max_length=255, blank=True)
    order = models.PositiveIntegerField(default=0)

Deleting Photos

Remove photos from your collection when needed.
1

Select Photo to Delete

In the photo management interface, click the delete button (trash icon) on the photo you want to remove.
2

Confirm Deletion

Confirm the deletion when prompted. This action cannot be undone.
3

Files Removed from Storage

The Photo.delete() method:
  • Removes the database record
  • Deletes the original image file from item_photos/
  • Deletes the AVIF version from item_photos_avif/
  • Cleans up storage to free space
# From models.py
def delete(self, *args, **kwargs):
    # Store file names before deletion
    image_name = self.image.name if self.image else None
    avif_name = self.image_avif.name if self.image_avif else None
    
    # Call parent delete to remove from database
    super().delete(*args, **kwargs)
    
    # Remove files from storage
    if image_name and image_storage:
        if image_storage.exists(image_name):
            image_storage.delete(image_name)
    # ... (same for AVIF)
Deleting a photo is permanent. The files are removed from storage and cannot be recovered. Make sure you have backups if needed.

External Image Handling

When using FKAPI integration, FootyCollect can download and import images from the Football Kit Archive.

How It Works

1

Image URLs Provided

When you select a kit from FKAPI search:
  • main_img_url - Primary kit image URL
  • external_image_urls - Comma-separated additional image URLs
These are hidden fields in the form.
2

Image Proxying

External images are proxied through FootyCollect to handle hotlink protection:Proxy Endpoint: /collection/proxy-image/?url={encoded_url}The proxy:
  • Validates the URL is from allowed hosts (cdn.footballkitarchive.com, etc.)
  • Adds proper Referer header to bypass hotlink protection
  • Limits image size (10MB max)
  • Streams the image to the browser
3

Background Download

When you save the item, external images are downloaded asynchronously:
  • Main image is downloaded first (order = 0)
  • Additional images follow (order = 1, 2, 3…)
  • Each is saved as a Photo record
  • AVIF processing is queued for each photo
4

Photo Association

Downloaded photos are associated with the item:
  • content_type = BaseItem content type
  • object_id = Item’s ID
  • user = Your user ID
Your uploaded photos are added after external images with the correct order offset.
External image downloads happen in the background. The item is created immediately, and photos appear as they’re downloaded and processed.

Orphaned Photo Cleanup

FootyCollect automatically manages temporary photos that aren’t associated with items.

What Are Orphaned Photos?

Photos are “orphaned” when:
  • Uploaded during item creation but the item wasn’t saved
  • Associated with a user but not linked to any item (object_id is NULL)
  • Left over from canceled or failed item creation

Automatic Cleanup

A scheduled Celery task runs periodically to clean up orphaned photos:
# Setup with: python manage.py setup_beat_schedule
# Runs every 24 hours (configurable in Django Admin)
The cleanup task:
  1. Finds photos where object_id IS NULL and user IS NOT NULL
  2. Checks if the photo is older than the retention period (e.g., 24 hours)
  3. Deletes the photo and its associated files
  4. Frees up storage space
You can adjust cleanup frequency in Django Admin under django_celery_beatPeriodic tasks. The default is once per day.

Photo Service Layer

FootyCollect uses a service layer for photo operations:
from footycollect.collection.services import get_photo_service

photo_service = get_photo_service()

Available Methods

MethodPurpose
create_photo_with_validation()Upload photo with validation
reorder_photos()Change photo order
delete_photo()Remove photo and files
process_external_images()Download from URLs
check_processing_status()Get AVIF conversion status

Best Practices

Upload high-quality originals - FootyCollect optimizes them automatically. Don’t pre-compress or resize images.
Use descriptive captions - Help future you remember important details about each photo.
Main photo matters - The first photo represents your item in lists. Choose a clear, well-lit front view.
Document condition - Photograph any damage, wear, or special features. Use captions to note details.
Demo mode has upload limits. Monitor your usage and delete unnecessary photos to stay within quota.

Troubleshooting

Photos Not Processing

If photos remain in “processing” state:
  1. Check the processing status endpoint for your item
  2. The system auto-retries failed processing every 120 seconds
  3. Verify Celery workers are running: celery -A config.celery_app worker -l info

Upload Limits

If you hit upload limits in demo mode:
  1. Check current usage vs. limit (shown in error message)
  2. Delete old or unnecessary photos
  3. Consider upgrading to a production deployment (no limits)

Missing AVIF Images

If optimized images aren’t loading:
  1. Check if image_avif field has a value
  2. Verify the file exists in storage
  3. FootyCollect falls back to original image if AVIF is missing
  4. The get_image_url() method handles this automatically

Next Steps