Using Digikam-DB

This document assumes that you are reasonably familiar with Digikam. If using MySQL, some knowledge about MySQL database setup and user management is helpful. You need not be an expert - if you managed to set up the database for Digikam, you should be fine. While Digikam-DB tries to encapsulate most of the internal database structure, a basic understanding of relational databases and the SQLAlchemy ORM is also helpful.

Accessing Digikam Databases

Digikam uses a SQLite or MySQL database to store its metadata. Access to the database is provided by the Digikam class. There are several ways to specify the Digikam database:

  • Digikam-DB can use the Digikam configuration:

    from digikamdb import Digikam
    dk = Digikam('digikamrc')
    
  • Use a database URL suitable for SQLAlchemy’s create_engine() function. For example, the default location (SQLite database) can be accessed with

    import os
    from digikamdb import Digikam
    dk = Digikam('sqlite:///' + os.path.expanduser('~/Pictures/digikam4.db'))
    

    A MySQL database on a DB server can be accessed with

    from digikamdb import Digikam
    dk = Digikam('mysql+pymysql://user:passwd@mysql.mydomain.org/mydatabase')
    

    For specification of the database, use the values you entered in the Digikam database configuration. With MySQL, you can also use a different user with reduced rights (e.g. only SELECT and SHOW VIEW) to keep your database safe if you do not need write access.

  • You can also use a previously created SQLAlchemy Engine object. This example uses the same database as the previous one:

    from sqlalchemy import create_engine
    from digikamdb import Digikam
    engine = create_engine('mysql+pymysql://user:passwd@mysql.mydomain.org/mydatabase')
    dk = Digikam(engine)
    

See also

Root Overrides

In some situations, Digikam-DB may need hints to find the path to your albums. With the root_override argument of Digikam, you can provide the location of an album root manually. There are different ways to specify the path to the album root:

dk = Digikam(
    my_database,
    root_override = {
        'ids': {
            'volumeid:?uuid=69bcae9a-608b-11ee-9c1b-939c964e84aa': '/data/pics1',
            23: '/data/pics2',
        },
        'paths': {
            'volumeid:?uuid=69bcae9a-608b-11ee-9c1b-939c964e84aa/pics3': '/data/pics3',
            42: '/data/pics4',
        }
    }
)

Entries in ids give substitutions for the identifier column in the AlbumRoots table. The roots can be specified by the row’s id or by its identifier (usually containing a volume ID like in the example above). The latter affects all album roots with the same identifier.

Entries in paths give substitutions for the whole path. The roots can be specified by the row’s id or by the combination of identifier and specificPath.

Entries in paths take precedence over entries in ids. Specification by id takes precedence over identifier (and specificPath).

Database Commits

Digikam-DB does not do commits by itself, allowing you to control which operations belong to a transaction. This means that transactions containing write operations have to be committed manually at appropriate places to make sure your changes are actually written to the database. The session property contains the SQLAlchemy session and can be used to do this (dk.session.commit() in the examples above).

General API Structure

Digikam Object Properties

Data stored in the database can be accessed through properties of the Digikam class, as described in the following chapters. The properties are

With the exception of settings, these properties behave alike:

  • The properties are iterable, yielding objects of the respective type (Image, Album, AlbumRoot or Tag). These classes are mapped to the respective database tabley by SQLAlchemy.

  • Individual objects can be accessed by their id via the [] operator. Some classes allow additional values for [] or offer methods to find objects with certain values.

  • Related objects can be accessed through properties of the original object, e.g. an image’s tags are stored in image.tags. These properties are lists or SQLAlchemy Query objects. The latter are iterable, but can be further refined (see below).

  • If you need access to the mapped class for an object type, it is stored in the property.Class of the appropriate Digikam property.

See the API documentation for details.

SQLAlchemy Query Objects

SQLAlchemy Query objects contain a database query that has not yet been executed, so the query can be modified by adding method calls to adjust the result to require less post-processing by code. The available methods include:

filter():

Sets a WHERE clause

filter_by():

Filters by attributes

order_by():

Sorts the result

first():

Returns the first result

one():

Returns exactly one object

one_or_none():

Returns one object, or None

all():

Returns the whole result as a list.

See the Query class documentation for more information.

Working with Images

Note

Digikam-DB does not directly support creating new images, or deleting, renaming or moving existing ones.

Retrieving Images

Images can be accessed through the images property of the Digikam class in different ways (dk is a Digikam object, see above):

  • Iterating over all images:

    for image in dk.images:
        print(image.id, image.name, image.abspath)
    
  • Via the [] operator:

    image = dk.images[23]               # id == 23
    

    To access images by name, use the find method.

  • Via the find() method:

    for image in dk.images.find('/path/to/dir/with/images'):
        print(image.id, image.name, image.abspath)
    

    find searches a path (which can be a directory or a file) and returns a list of all matching images.

  • Via a the select() method:

    # Find all images named 'my_image.jpg'
    imglist = dk.images.select(name = 'my_image.jpg')
    
    # Find all images larger than 3MB:
    imglist = dk.images.select('fileSize > 3000000')
    
    # Find all images modified in 2020 or later:
    imglist = dk.images.select("modificationDate >= '2020-01-01 00:00:00'")
    

    select() supports the following attributes:

See also

Titles and Captions

Titles and captions are text fields usually containing descriptive information about the image. Both are multi-lingual, captions can also have an author and a date. They are accessed via the Image properties titles and captions. For both, there is a “quick access” attribute:

  • title: language = x-default

  • caption: language = x-default, auhtor = None

The “plural” properties can be used to access other titles and captions.

print(img.title)                # print title in 'x-default'
print(img.titles['x-default'])  # same as above

print(img.caption)              # print caption in 'x-default', no author
print(img.captions[('x-default', None)]
                                # same as above

img.titles['de-DE'] = 'Ein Titel'   # German title
img.titles['fr-FR'] = 'Un titre'    # French title

See also

Tags

See Accessing an Image’s Tags.

Working with Albums

Albums in Digikam are actually directories in the file system. They are shown as a tree in digikam, but the database does not reflect that.

Note

  • Digikam-DB does not directly support creating new albums, or deleting existing ones.

  • New album roots can be added through Digikam-DB, but have to be populated with albums and images by Digikam.

Retrieving Albums

Albums can be accessed through the albums property of the Digikam class in different ways (dk is a Digikam object, see above):

  • Iterating over all albums:

    for album in dk.albums:
        print(album.id, album.caption, album.abspath)
    
  • Via the [] operator:

    album = dk.albums[42]               # id == 42
    

    To access albums by directory, use the find method.

  • Via the find() method:

    for album in dk.album.find('/path/to/dir/with/images'):
        print(album.id, album.caption, album.abspath)
    

    find searches a path (which can be a directory or a file) and returns a list of all matching albums.

  • Via a the select() method:

    # Find all albums in collection 'family'
    alblist = dk.albums.select(collection = 'family')
    
    # Find all albums whose captionn contains 'vacation'
    alblist = dk.albums.select("caption like '%vacation%'")
    
    # Find all albums modified in 2020 or later:
    alblist = dk.albums.select("date >= '2020-01-01 00:00:00'")
    

    select() supports the following attributes:

See also

Working with Tags

Digikam keeps a table of all defined tags with their properties, and another table containing the assignment of tags to images (or vice versa). Thus tags can be accessed globally or as tags assigned to an image.

Accessing Globally Defined Tags

Tags can be accessed through the tags property of the Digikam class in different ways (dk is a Digikam object, see above):

  • Iterating over all tags:

    for tag in dk.tags:
        print(tag.id, ':', tag.name)
    
  • Via the [] operator:

    tag = dk.tags[23]               # by id
    tag = dk.tags['My Tag']         # by name
    tag = dk.tags['parent/child']   # by hierarchical name
    

    To access a tag by name this way, the name has to be unique, or an exception is raised. To access tags by a non-unique name, use the select() method.

    If no matching tag is found, an Exception is raised.

  • Via a SELECT with certain attributes:

    for tag in dk.tags.select(name = 'My Tag'):
        print(tag.hierarchicalname())
    

New tags can be created with the add() method:

# Tag at top level without an icon
my_tag = dk.tags.add('My Tag', 0)

# Tag with parent 'Friends' and KDE icon tag-people
chris = dk.tags.add('Chris', dk.tags['Friends'], 'tag-people')

# Save changes to database
dk.session.commit()

The optional third argument specifies the tag’s icon. It can be an Image obect, an int or a str. When given as a str, the icon is assumed to be a KDE icon specifier. Otherwise, it should be an image from the database.

See also

Accessing an Image’s Tags

The tags of an image are stored in its tags property (img is an Image object, see above):

for tag in img.tags:
    print(tag.name)

The tags property is actually a Query object, so you can refine it further:

# Iterate over all tags that have the KDE icon tag-people
for tag in img.tags.filter_by(iconkde = 'tag-people'):
    print('Tag', tag.name, 'has icon <tag-people>')

# Get the tag with id 42, or None if the image has no such tag
forty_two = img.tags.filter_by(_id = 42).one_or_none()

A Tag object also has an images property containing all Images that have the tag set:

# Get all images in album with id=42 and tag 'My Tag'
for img in dk.tags['My Tag'].images.filter_by(_album = 42):
    print('Image', img.name, 'has tag <My Tag>')

To add a tag to an image, modify its tags property:

# Add tag to image
img.tags.append(tag1)

# Remove another tag from image
img.tags.remove(tag2)