Pattern 1: Basic CRUD Operations
Creating Entities
- New entities get automatic UUID4 IDs (32-char hex strings)
.save(client)executes the appropriate GraphQL mutation- Server-assigned ID replaces the UUID4 after save
- Use
entity.is_new()to check if entity has been saved
Reading/Querying Entities
find_X(id)methods return single entity or Nonefind_Xs(filter)methods return result objects with count and items- Result objects have entity-specific list names (e.g.,
scenes,performers) - Pagination handled via
pageandper_pageparameters
Updating Entities
- Only modified fields are sent in update mutations
- Use
UNSETto explicitly not modify a field get_changed_fields()shows what will be sent- Entity
.save()automatically chooses create vs update mutation
Deleting Entities
.delete(client)available on entity types with__destroy_input_type__- Client also has
X_destroy({"id": ...})methods - Deletion is permanent - no undo
Pattern 2: Working with Relationships
Setting Single Relationships (Many-to-One)
- Set relationship by assigning entity object
- Bidirectional sync happens automatically
- Save the entity to persist the relationship
- Inverse field only synced if it was loaded
Setting Many-to-Many Relationships
- Many-to-many relationships are lists
- Can assign entire list or use
add_X()/remove_X()helpers - Helper methods automatically sync inverse relationships
- Changes persist only after
.save(client)
Querying Related Entities
- Always check for UNSET before accessing relationships using
is_set() - Related entities automatically cached in identity map
- Same entity ID = same object reference everywhere
Pattern 3: Using the Entity Store
Basic Store Operations
get()fetches from server if not in cacheget_cached()only checks cache, never queries- Store methods wrap client methods with caching
- TTL optional (None = never expire)
Django-Style Filtering
__exact- Exact match__contains- String contains__regex- Regular expression match__gte,__gt- Greater than (or equal)__lte,__lt- Less than (or equal)__between- Range (tuple of min/max)__null- Null check (boolean)__in- List membership
Field-Aware Population
_received_fieldstracks which fields were loadedmissing_fields()returns set of fields not yet loadedpopulate()fetches only missing fields- Use
force_refetch=Trueto invalidate cache and reload
Lazy Iteration for Large Result Sets
find_iter()yields items one at a time- Pages fetched on demand (not all upfront)
- Can break early to save network requests
query_batchcontrols page size (default 40)
Pattern 4: Advanced Queries
Using Raw GraphQL Filters
- Raw filters give full control over GraphQL query
- Use when Django-style syntax is insufficient
- Filter structure matches Stash’s GraphQL schema
- See API reference for available modifiers
Pagination
pageis 1-indexed (first page = 1)per_pagedefaults to 40 (max typically 1000)- Check
len(result.items) < per_pageto detect last page - Result object includes
.countfor total items
Pattern 5: Bulk Operations
Concurrent Fetches
Concurrent Updates
- Use
asyncio.gather()for concurrent operations - Be mindful of rate limits (don’t send 1000 concurrent requests)
- Consider batching (process 10-50 at a time)
Batch Processing with Progress Tracking
Pattern 6: Job Management
Starting and Monitoring Jobs
Polling Job Status
Using Subscriptions for Real-Time Updates
metadata_scan(),metadata_generate()return job IDswait_for_job()blocks until completion (with timeout)- Manual polling gives more control over progress updates
- Subscriptions provide real-time updates via WebSocket
Pattern 7: ID Mapping and Utilities
Converting Names to IDs (with Auto-Create)
map_performer_ids(items, create=False)map_studio_ids(items, create=False)map_tag_ids(items, create=False)
- Pass list of strings (names) or entity objects
create=Truecreates missing entities- Returns list of IDs in same order as input
- Mixed types supported (strings and objects)
Studio Hierarchy Navigation
Pattern 8: Error Handling
Handling GraphQL Errors
Handling Validation Errors
Handling Connection Errors
Next Steps
- Overview Guide - Architecture and core concepts
- UNSET Pattern Guide - Deep dive on partial updates
- API Reference - Complete method documentation
- Architecture Details - Implementation deep dives