Skip to main content

Creating and editing *.apkg and *.anki2 safely

Project description

AnkiSync 2

PyPI version PyPI license

*.apkg and *.anki2 file structure is very simple, but with some quirks of incompleteness.

*.apkg file structure is a zip of at least two files.

├── example
│   ├── example.anki2
│   ├── media
│   ├── 1  # Media files with the names masked as integers
│   ├── 2
│   ├── 3
|   └── ...
└── example.apkg

*.anki2 is a SQLite file with foreign key disabled, and the usage of some JSON schemas instead of some tables

Also, *.anki2 is used internally at os.path.join(appdirs.user_data_dir('Anki2'), 'User 1', 'collection.anki2'), so editing the SQLite there will also edit the database.

The media file is a text file of at least a string of {}, which is actually a dictionary of keys -- stringified int; and values -- filenames.


Some extra tables are created if not exists.

from ankisync2.anki import Anki2, Apkg
apkg = Apkg("example.apkg")  # Or Apkg("example/") also works, otherwise the folder named 'example' will be created.
apkg.db.execute_sql(SQL, PARAMS)"example1.apkg")

I also support adding media.


To find the wanted cards and media, iterate though the Apkg and Apkg.iter_media object.

iter_apkg = iter(apkg)
for i in range(5):

Creating a new *.apkg

You can create a new *.apkg via Apkg with any custom filename (and *.anki2 via Anki2()). A folder required to create *.apkg needs to be created first.

from ankisync2.anki import Apkg
apkg = Apkg("example")  # Create example folder

After that, the Apkg will require at least 1 card, which is connected to at least 1 note, 1 model, 1 template, and 1 deck; which should be created in this order.

  1. Model, Deck
  2. Template, Note
  3. Card
from ankisync2 import db
m = db.Models.create(name="foo", flds=["field1", "field2"])
d = db.Decks.create(name="bar::baz")
t = [
    db.Templates.create(name="fwd",, qfmt="{{field1}}", afmt="{{field2}}"),
    db.Templates.create(name="bwd",, qfmt="{{field2}}", afmt="{{field1}}")   
n = db.Notes.create(, flds=["data1", "<img src='media.jpg'>"], tags=["tag1", "tag2"])
c = [
    db.Cards.create(,, ord=i)
    for i, _ in enumerate(t)

You can also add media, which is not related to the SQLite database.


Finally, finalize with"example1.apkg")

Updating an *.apkg

This is also possible, by modifying as sqlite_ext.JSONField, with peewee.signals.

It is now as simple as,

from ankisync2.anki import Apkg
from ankisync2 import db

apkg = Apkg("example1.apkg")

for n in db.Notes.filter(["field1"] == "data1"):["field3"] = "data2"


JSON schema of Col.models, Col.decks, Col.conf and Col.dconf

I have created dataclasses for this at /ankisync2/ To serialize it, use dataclasses.asdict or

from ankisync2.util import DataclassJSONEncoder
import json
json.dumps(dataclassObject, cls=DataclassJSONEncoder)

For an example of how this works, please see /ankisync2/

Using peewee framework

You can also use peewee ORM framework; and ArrayField, X1fField and JSONField will be automated. You can use Dataclasses and Lists directly, without converting them to string first.


Please see /example.ipynb.


pip install ankisync2

Related projects

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for ankisync2, version
Filename, size File type Python version Upload date Hashes
Filename, size ankisync2- (11.3 kB) File type Wheel Python version py3 Upload date Hashes View hashes
Filename, size ankisync2- (12.3 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page