archivebox.base_models.admin

Base admin classes for models using UUIDv7.

Module Contents

Classes

HexUUIDConverter

URL path converter that canonicalizes UUIDs to their 32-char hex form.

ConfigOption

KeyValueWidget

A widget that renders JSON dict as editable key-value input fields with + and - buttons to add/remove rows. Includes autocomplete for available config keys from the plugin system.

ConfigEditorMixin

Mixin for admin classes with a config JSON field.

BaseModelAdmin

API

class archivebox.base_models.admin.HexUUIDConverter[source]

URL path converter that canonicalizes UUIDs to their 32-char hex form.

Accepts both the hyphenated (aaaaaaaa-bbbb-...) and bare-hex (aaaaaaaabbbb...) UUID strings on the way in (Django’s UUIDField parses either), but to_url always emits the bare-hex form. This is what makes reverse("admin:app_model_change", args=[obj.pk]) produce /admin/app/model/06a1a8facb0d.../change/ instead of the default hyphenated rendering — admin links throughout the app reverse through this converter once BaseModelAdmin.get_urls swaps in <hexuuid:object_id> below.

regex[source]

‘[0-9a-fA-F]{32}|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}’

to_python(value: str) str[source]
to_url(value) str[source]
class archivebox.base_models.admin.ConfigOption[source]

Bases: typing.TypedDict

plugin: str[source]

None

type: str | list[str][source]

None

default: object[source]

None

description: str[source]

None

enum: NotRequired[list[object]][source]

None

pattern: NotRequired[str][source]

None

minimum: NotRequired[int | float][source]

None

maximum: NotRequired[int | float][source]

None

class archivebox.base_models.admin.KeyValueWidget[source]

Bases: django.forms.Widget

A widget that renders JSON dict as editable key-value input fields with + and - buttons to add/remove rows. Includes autocomplete for available config keys from the plugin system.

template_name = <Multiline-String>[source]
class Media[source]
css[source]

None

js[source]

[]

_get_config_options() dict[str, archivebox.base_models.admin.ConfigOption][source]

Get available config options from plugins.

_parse_value(value: object) dict[str, object][source]
render(name: str, value: object, attrs: collections.abc.Mapping[str, str] | None = None, renderer: django.forms.renderers.BaseRenderer | None = None) django.utils.safestring.SafeString[source]
_render_row(widget_id: str, key: str, value: str) str[source]
_escape(s: object) str[source]

Escape HTML special chars in attribute values.

value_from_datadict(data: django.http.QueryDict | collections.abc.Mapping[str, object], files: object, name: str) str[source]
class archivebox.base_models.admin.ConfigEditorMixin[source]

Bases: django.contrib.admin.ModelAdmin

Mixin for admin classes with a config JSON field.

Provides a key-value editor widget with autocomplete for available config keys.

formfield_for_dbfield(db_field: django.db.models.Field, request: django.http.HttpRequest, **kwargs: object) django.forms.Field | None[source]

Use KeyValueWidget for the config JSON field.

save_model(request: django.http.HttpRequest, obj, form, change)[source]

Preserve write-only redacted credentials on save.

The KeyValueWidget renders sensitive keys (*TOKEN*, *SECRET*, *API_KEY*, *APIKEY*) with an empty value + password input — the real value never leaves the server. On submit, an empty value for a sensitive key that was previously set means “leave untouched”, not “clear it.” We honor that here by re-merging the stored value before the row is written. Explicitly removing the row in the UI still clears it (the key is gone from the submitted JSON, so there’s nothing to merge over).

class archivebox.base_models.admin.BaseModelAdmin[source]

Bases: django_object_actions.DjangoObjectActions, django.contrib.admin.ModelAdmin

list_display[source]

(‘id’, ‘created_at’, ‘created_by’)

readonly_fields[source]

(‘id’, ‘created_at’, ‘modified_at’)

show_search_mode_selector[source]

False

get_default_search_mode() str[source]
get_form(request: django.http.HttpRequest, obj: django.db.models.Model | None = None, change: bool = False, **kwargs: object)[source]
get_urls()[source]

Swap the per-object admin URLs from <path:object_id> to <hexuuid:object_id> so canonical change/delete/history URLs use the 32-char hex form. The hyphenated form still resolves because the converter’s regex accepts both — Django reverses through to_url which always emits hex, so links in templates / changelists / inline formsets all canonicalize automatically.

Non-UUID PKs (an IntegerField PK on some legacy table, for example) won’t match the converter’s regex and fall back to the default <path:object_id> patterns we still include after our swap.