conjunto

Django application framework/helpers using HTMX, tabler.io, tables2, crispy-forms & more.

conjunto.cms

This is a django app for providing content management system functionality.

admin

models

LicensePage

Bases: VersionedPage

A page that holds the license information for this software.

PrivacyPage

Bases: VersionedPage

A page that holds the privacy information for this software.

StaticPage

Bases: Page

A page that holds static content.

conjunto.components

DataGrid

Bases: Component

The DataGrid class is a component that generates a data grid for displaying data in a tabular format.

It automatically determines all regular model fields and shows their translated title. It also detects properties/getters instead of fields, the component tries to find out a proper name as title here by creating a capitalized version of the property name and translating it into the locale language. However, you have to provide a proper translation string for your property name in your .po file manually.

Note To keep Django's makemessages from commenting out these "unused" translations, just add an unused _("...") string anywhere into your method. E.g. when your property is named "display_name()", just add a _("Display name") anywhere into this method block. This keeps Django from garbage collecting this translation.

Attributes:
  • object

    the Django model object to display

  • fields

    a comma separated list of field names to display

Example usage:

{% #datagrid object=request.user fields="first_name,last_name,email" %}
get_context_data(**kwargs)

renders fields of given object in a datagrid-usable form.

List

Bases: Component

A flexible component to display a Tabler.io list.

Attributes:
  • items

    the list of objects to display. Should be a queryset.

  • hoverable

    whether the list items are hoverable or not.

Updateable

Bases: Component

HTML element that updates itself using HTMX when a certain Javascript event is triggerd anywhere in the body.

Attributes:
  • id

    the id attribute of th div.

  • elt

    the HTML element that should be rendered. Default: div

  • trigger

    the Js event that should trigger the update

  • url

    the URL to call a get request to update the component

Example
{% updateable id="my-card" trigger="person:changed" url=request.path %}

{% url 'person:update' as person_update_url %}
{% updateable elt="ul" id="people-list" trigger="person:changed" url=person_update_url %}

conjunto.context_processors

conjunto.forms

DynamicHtmxFormMixin

Bases: DynamicFormMixin

Mixin class for creating dynamic forms with HTMX.

This mixin extends the functionality of the DynamicFormMixin by adding htmx attributes to the form fields that can be used for triggering dynamic updates.

Attributes:
  • context (dict[str, Any]) –

    The context passed to the form from the view. This variable can be accessed within the form via self.context.

  • form_id (str) –

    The id of the form. This is used to generate the id of the form, which is needed as HTMX target

  • Meta.trigger_fields (str) –

    A dict with field names as keys that will trigger a dynamic update on a list of fields (the dict values) on a "change" event.

  • Meta.update_url (str) –

    The URL to send the dynamic update request to. Defaults to current URL if not provided.

  • Meta.trigger (str) –

    the event that triggers the update. Defaults to "change".

Raises:
  • AttributeError

    If the trigger_fields attribute is not defined in Meta.

fields_required(fields, msg=None)

Helper method used for conditionally marking fields as required.

Parameters:
  • fields (str | list[str]) –

    A list of field names, or single field name.

  • msg (str, default: None ) –

    A custom error message. Defaults to "This field is required.".

Example usage:

def clean(self):
    is_person = self.cleaned_data.get("is_person")

    if is_person:
        self.field_required(["first_name", "last_name"])
        self.field_required("title", "A title is definitely required here.")
        self.field_required(["age", "size"], "You forgot this field.")
    else:
        self.cleaned_data["first_name"] = ""
        self.cleaned_data["last_name"] = ""
        self.cleaned_data["title"] = ""

    return self.cleaned_data

Credits go to https://www.fusionbox.com/blog/detail/creating-conditionally-required-fields-in-django-forms/577/

ErrorLogMixin

A mixin that can be added to a Form during development/debugging, so that it logs all form errors.

MyDynamicFormMixin

A mixin class for Django forms that allows dynamic fields to be included or excluded based on certain conditions.

Attributes:
  • context (dict[str, Any]) –

    The context passed to the form from the view. This variable can be accessed within the form via self.context.

  • Meta.excluded_fields_method (ExcludeMethod) –

    The method to use to if a field is excluded. The default is to hide the field (HIDE). DELETE removes the excluded field entirely from the form, and DISABLE disables the field.

widgets

DatePickerInput

Bases: DateInput

A DateInput that uses a date picker.

It adds Litepicker.js for that input field. Additionally, you can specify another field with "end_field_name" that is used for date ranges by Litepicker then.

conjunto.htmx

HxActionButton

Bases: HxButton

A renderable action button from an IActionButton instance.

Parameters:
  • request (HttpRequest) –

    the current request

  • action_button (IActionButton) –

    the IActionButton class

HxButton

Render a HTMX enabled button.

Attributes:
  • url

    the text to display

  • icon

    the (optional) icon to display

  • dialog

    whether to open a modal dialog (sets hx-target to #dialog)

  • target

    the target to open the link in. Cannot be used together with dialog.

  • css_class

    the css classes to apply to the button

  • method

    the method to call on click ("get" or "post"). Default is "get".

  • view_name

    the name of the view to call on click, if no url is provided. if provided, the render method must be called with url params if they are needed to create the url using reverse(view_name, kwargs)

Example
{% hx_button url="person:add" method="post" icon="plus" dialog=True css_class="btn"

Render a hyperlink using HTMX.

Attributes:
  • url

    the URL.

  • text

    the text to display.

  • icon

    the (optional) icon to display before the text.

  • dialog

    whether to open a modal dialog. Defaults to False.

IHtmxComponentMixin

Bases: HtmxResponseMixin

An interface Mixin that describes a component and can be rendered as plugin.

  1. Declare an interface for HTMX components
  2. Declare Implementations of that interface which also inherit from View.

Examples:

# in your plugin's api/interfaces.py, create an interface for your view
@Interface
class IUserProfileSection(IHtmxComponentMixin, ...):
    params = ["pk"]
    template_name = "common/layout/profile_section.html"
    ...

# in your plugin's views.py
def PasswordView(IUserProfileSection, UpdateView)
    ...
def OtherComponentView(IUserProfileSection, TemplateView)
    ...

Use them in your template:

{% for plugin in components.IUserProfileSection %}
    <a href="#"
       hx-get="{% url component.get_url_name user.id %}"
       hx-trigger="{% if component.selected %}load, {% endif %}click once"
       {# hx-push-url="{{ component.name }}" #}
       hx-target="#profile-content"
       class="list-group-item list-group-item-action d-flex align-items-center
        active">
        <i class="bi bi-{{ component.icon }} me-2"></i>
        {{ component.title }}
     </a>
{% endfor %}

You can also inherit from other mixins, e.g. PermissionRequiredMixin, etc.

class UserprofilePasswordSection(
    IUserProfileSection, PermissionRequiredMixin, TemplateView
):
    name = "password"
    permission_required = "..."
    template_name = "my_app/password_view.html
form_kwargs_request = False class-attribute instance-attribute

Should the evtl. attached form receive a request?

group = '' class-attribute instance-attribute

The group this component lives under. Can be used to display group headers.

icon: str = '' class-attribute instance-attribute

the icon name, if the component is listed in a list, and icons are used.

name: str = '' class-attribute instance-attribute

The view name of the component. Must be unique. Used in and URLs. Can be used for HTML attributes.

params: list[str] = [] class-attribute instance-attribute

A list of params the view is using. These must then be passed when calling the view from a template, e.g. via hx-get.

title: str = '' class-attribute instance-attribute

The title this plugin is rendered with. It's up to you how the plugin uses that title.

weight: int = 0 class-attribute instance-attribute

The weight this component is ranked like menu items. The more weight, the more the component sinks "down" in the list.

enabled()

Hook for implementations to define if the component is enabled.

Returns:
  • bool

    True if the component is enabled, False if not.

get_name()

Returns the component's view (machine) name.

get_title()

returns the component's title.

Use it in templates like {{ component.get_title }}

get_url_name()

Returns the component's url.'

Use it as {% url component.get_url ... %} in a template.

get_url_patterns() classmethod

Convenience method to add to your urls.py in an include section:

Example
url_patterns = [
    path(...),
    path("profile/",
        include(
            (IUserProfileSectionView.get_url_patterns(), "profile"),
            namespace="profile"
        )
    ),
]

# or directly add the url_patterns to the main list:

url_patterns += IUserProfileSectionView.get_url_patterns()
get_urlpattern()

Calculates the urlpattern where this component is accessible.

That can be used e.g. in hx-get attributes. Returns: a URLPattern that can be used in your urls.py

Icon

Render an icon using Bootstrap 5.

Attributes:
  • name

    the name of the icon

UseComponentMixin

A mixin that can be added to a View that uses HTMX components.

This can be used if e.g. a View has tabs, or variable parts of the page that are extended by a component. The URL is pushed automatically with the new component as configurable GET parameter, e.g.: example.com/persons/42?tab=account

Example
class MyView(UseComponentMixin, DetailView):
    components = [PersonAccountTab]
Attributes:
  • components (list[IHtmxComponentMixin]) –

    a list of Interfaces that are used in the template of this view, and can be accessed there using components.IFooInterface.

query_variable = 'tab' class-attribute instance-attribute

The query variable that is used to indicate the active component.

conjunto.http

HttpResponseEmpty

Bases: HttpResponse

An HTTP response that has no content.

Used for HTMX requests that should not return anything, like delete requests. The returned status code is 204.

HttpResponseHXRedirect

Bases: HttpResponseRedirect

A Http response that redirects a HTMX request to the location given in redirect_to

conjunto.management

commands

update_permissions
Command

Bases: Command

Reload permissions of all (given) apps.

Checks all (given) apps for a group_permissions attribute and creates Group permissions using that schema.

# apps.py
import ...

class MyPackageCppConfig(AppConfig):
    group_permissions: {
        "Authors": { my_package.MyContentTypeModel: ["view", "change"],
        # on my special site, admins may not change content, just add/delete it!
        "Site admins": { "my_package.MyContentTypeModel": ["view", "add", "delete"],
    }

conjunto.menu

IActionButton

Bases: MenuItemInterfaceMixin

An action button that can be added to an e.g. table row.

Attributes:
  • view_name (str) –

    The name of the view that should be called when this button is clicked. It will get the current row's object as param.

  • method

    the method to call the request: "get" (default) or "post".

IMenuItem

Bases: MenuItemInterfaceMixin

An extendable and versatile MenuItem Interface

You can use that for creating menu items in a named menu:

class AddUserAction(IMenuItem)
    menu = "page_actions"
    title = _("Add user")
    url = reverse_lazy("user:delete")
    icon = "user-delete"
Attributes:
  • url (str) –

    the URL to call when this menu item is clicked.

  • separator (bool) –

    if True, this menu item has a separator after it.

  • badge (str) –

    a callable that returns a string to be displayed in a badge.

  • exact_url (bool) –

    if True, the active class will only get added on the menu item if the browser path matches exactly the MenuItem URL. If False (default), it also is active when child items are selected.

  • collapsed (bool) –

    If True, this menu item is collapsed by default.

selected()

Check current URL against this item.

Menu

Represents a named menu during a request.

Usually it is used in Django templates by calling menus.<name> which then will return all MenuItems with a matching "menu" name attribute. Therefore, Menu will be instantiated by a context_processor, so that the menu variable in the template

<ul>
{% for item in menus.user %}
    <li><a href="{{item.url}}">{{ item.title }}</a></li>
{% endfor %}
</ul>
__getitem__(item)

Returns filtered out menu items with the given '.menu' name.

MenuItemInterfaceMixin

A mixin that provides common functionality for menu items or action buttons etc.

Attributes:
  • title (str) –

    the (translatable) title that should be displayed in the menu.

  • menu (str) –

    The menu name where this MenuItem should be rendered. Can be any string. This menuitem is then found in templates under the menu.<this-menu-attr> menu. If you don't specify a menu, "main" is used.

  • weight (int) –

    The "weight" of the menu. The higher the weight, the more it "sinks" down in the menu. Default: 0

  • icon (str) –

    The (Bootstrap) icon name to display, if the menu shows icons.

  • slug (str) –

    The slug (machine name) of the item, used for css classes etc. If not provided, it is auto-generated from the title.

  • view_name (str) –

    The name of the view (in the form 'module:view-name', like in urls.py) under which this menu item should show up. If left empty, the menu item will show up under all views.

  • required_permissions (list) –

    The permissions necessary to view this menu item.

    Warning

    this has nothing to do with the required permissions to call the URL that this MenuItem points to. You must make sure for yourself that the required permissions are checked correctly at the view.

  • disabled (bool) –

    bool = False

  • visible (bool) –

    If True, this item is visible.

  • check (bool) –

    A callable that returns True if the item should be displayed, False otherwise.

__getattr__(item)

For all attrs that are requested in the template and are not defined in the class, don't produce an error, just return an empty string.

children()

Returns an iterable of all children of this menu item.

filter(name) classmethod

Filter the menu items by the 'menu' key name.

has_children()

Returns True if this menu item has children, False otherwise.

has_parent()

Returns True if this menu item has a parent, False otherwise.

conjunto.middleware

HtmxMessageMiddleware

Filters out django messages and puts them in to the HX-Trigger header if current request is a HTMX request

conjunto.models

AbstractSettings

Bases: SingletonModel

Represents the settings of the application.

This model is meant to be subclassed by your application. Please add application specific settings as needed to this model.

Page

Bases: Model

Represents a generic page.

This class is an abstract base class that provides common fields and methods for all page subclasses.

SingletonModel

Bases: Model

Singleton Django Model.

Allow only one instance of the model to be created. To get the instance of the model, use <YourModel>.get_instance().

get_instance() classmethod

Load object from the database.

Failing that, create a new empty (default) instance of the object and return it (without saving it - you have to do that yourself).

Raises:
  • IntegrityError

    if there are more than one objects saved in the databases.

save(*args, **kwargs)

Save object to the database.

Raises:
  • IntegrityError

    if there is already another instance in the database.

VersionedPage

Bases: Page

Represents a generic page with versioning.

This class is an abstract base class that provides common fields and methods for all page subclasses.

conjunto.tables

ActionButtonType

Bases: IntegerChoices

Action buttons type, and their weights.

ActionButtonsTable

Bases: UpdateTableMixin, Table

A table mixin that provides an "actions" column for row actions.

The table will update itself if a given event is triggered. Per default, the actions column is positioned at the end via Meta.sequence. However, if you use your own Meta.sequence, don't forget to add the "actions" column at the end.

Parameters:
  • record_view_name (str, default: None ) –

    View name for the model of the record, like <app_name>:<model_name>. This is used to determine the action URLs for the action buttons, and to create the listen events for the table.

  • standard_buttons (list[ActionButtonType], default: None ) –

    List of standard action buttons to render. Change this if you e.g. want to use a DELETE_WITH_CONFIRM button instead of a DELETE button.

  • action_buttons_menu (list, default: None ) –

    Menu name for IActionButtons that should be rendered additionally to the standard buttons.

render_actions(record)

sort all desired buttons (standard and IActionMenu generated) by weight, and render them.

UpdateTableMixin

A table mixin that that updates itself using HTMX when a javascript event is triggered.

Arguments in Meta class

conjunto.tools

camel_case2snake(camel_str, separator='_')

Converts a CamelCase string to snake_case.

country_code_from_locale(loc)

Extracts an (uppercase) country code from a locale

country_name_from_code(iso3166_code)

Returns the country name from a ISO 3166 Alpha2 country code.

create_groups_permissions(groups_permissions)

Creates groups and their permissions defined in given groups_permissions automatically.

Attributes:
  • groups_permissions

    a dict, see also [PluginAppConfig.groups_permissions]

get_system_locales(strip_c=True)

Finds locales installed on a POSIX system and returns a list.

Parameters:
  • strip_c (bool, default: True ) –

    if True(default), remove C.* and POSIX from result

language_from_locale(loc)

Extracts a language code from a locale

snake_case2spaces(string)

Converts a snake_case string to spaces.

spaces2snake_case(string)

Converts a space separated string to snake_case.

str_to_bool(bool_str)

returns True if bool_str is "true", else False.

conjunto.views

AnonymousRequiredMixin

Bases: PermissionRequiredMixin

View mixin that only allows access for anonymous users.

AutoPermissionsViewMixin

Bases: PermissionRequiredMixin

Automatically uses view/create/change/delete permissions for the given model.

It automatically generates the "_" permission of the given model as necessary permission for this view.

Attributes:
  • __permissions_verb

    the verb to create the permissions: 'create' or 'change'

  • default

    "view"

DialogType

Bases: Enum

Enumeration of possible dialog levels.

Levels are used from Python's logging module

DynamicHtmxFormViewMixin

Bases: PrepopulateFormViewMixin

Mixin class for dynamic form views.

This mixin can be used with any FormView class to automatically prepopulate fields from GET parameters, and adds them to a "context" variable which is available within the form instance.

This view is intended to be used together with DynamicHtmxFormMixin for the form_class.

It creates a form_id (if not given) and passes it to the form. This is needed as HTMX target id.

GenericLicenseView

Bases: LatestVersionMixin, DetailView

Generic privacy page view that displays the newest LicensePage.

GenericPrivacyView

Bases: LatestVersionMixin, DetailView

Generic privacy page view that displays the newest PrivacyPage.

HtmxDeleteView

Bases: HtmxFormMixin, DeleteView

Enhanced DeleteView that per default returns an empty HttpResponse.

TODO either use success_url, OR success_event.
Attributes:
  • success_url

    the URL to redirect to. Defaults to None, in this case no redirection is made. If an URL is given, the client is redirected to that URL after successful deletion by using the HX-Redirect HTMX directive.

HtmxFormMixin

Bases: HtmxResponseMixin

Mixin for a form view that uses HTMX.

Returns an "Hx-Trigger" attribute which triggers a Javascript event on the client.

Attributes:
  • success_event

    a Javascript event that is triggered on the client after the request is completed.

form_valid(form)

Trigger a Javascript event on the client.

get_success_event()

Override this to return (e.g. generated) success event.

get_success_url()

Return an empty URL.

HtmxResponseMixin

View Mixin to add HTMX functionality.

optionally checks if request originates from an HTMX request.

Attributes:
  • enforce_htmx (bool) –

    if True, all requests that do not come from a HTMX component are blocked

  • success_event (bool) –

    a Javascript event that is triggered on the client after the request is completed.

Raises:
  • PermissionDenied

    if enforce_htmx==True and request origins from a non-HTMX caller.

HtmxTemplateMixin

If called from HTMX, this view renders template names with a "_htmx" suffix.

LatestVersionMixin

A mixin for views that require fetching the latest version of an object.

You can override the template in <your_app_name>/versioned_page.html.

Attributes:
  • title (str) –

    The title of the view.

  • no_object_available (str) –

    The message to display when no object is available.

ModalCreateView

Bases: PermissionRequiredMixin, ModalFormViewMixin, CreateView

Convenience CreateView (with permissions) that lives in a Modal.

It automatically generates the Modal title and sets the "create_" permission of the given model as necessary permission. Override as needed.

ModalFormViewMixin

Bases: HtmxFormMixin

Mixin for FormViews that should live in a modal.

It relies on crispy-forms intensively, and already provides a form helper instance attribute you can use.

In many cases, you need no template, as this mixin provides a generic one with a customizable title. The form is generated using crispy-forms. If you want to customize if further, then, extend "conjunto/modal-form.html". This template uses a header with a title block, a body, and a footer block to override, for your modal dialog. In the footer, there is always a "Cancel" button, and as default, a "Save" button, which you can override using the "footer" block.

When the modal pops up, the focus is set to the first visible input element.

You can customize the content of the "Save" button by changing the button_content attribute to another string.

If the form is saved successfully, it returns an empty HttpResponse(204) and emits the event specified in success_event on the client, so that it can reload changed content.

autofocus_field = '' class-attribute instance-attribute

The field that gets the autofocus when the modal is shown

button_content = _('Save') class-attribute instance-attribute

The content of the 'Save' button

dialog_type: DialogType = DialogType.NOTSET class-attribute instance-attribute

The type of the dialog: INFO,

form_layout: list = [] class-attribute instance-attribute

The crispy forms layout for the form

modal_title: str = '' class-attribute instance-attribute

The title of the modal form

template_name = 'conjunto/modal-form.html' class-attribute instance-attribute

The default template name for the modal form. This template provides a simple modal form. You can extend it in your own templates too.

get_modal_title()

Returns a string that is used as title of the modal.

ModalUpdateView

Bases: _ModalModelViewMixin, UpdateView

Convenience UpdateView (with permissions) that lives in a Modal.

It automatically generates the Modal title and sets the "change_" permission of the given model as necessary permission. Override as needed.

PrepopulateFormViewMixin

A mixin class that prepopulates form fields with values from the request.GET parameters.

This mixin can be used with any FormView class to automatically prepopulate form fields with values from the URL query string parameters.

Example usage:

class MyFormView(PrepopulateFormMixin, FormView): form_class = MyForm template_name = 'my_template.html' success_url = reverse_lazy('my_success_url')

In the above example, the form fields will be prepopulated with values from the URL query string parameters when the form view is loaded.

get_initial()

Returns the initial data for the form.

clean_dict(input_dict)

Clean the input dictionary by removing any key-value pairs where the value is "undefined".

:param input_dict: The input dictionary to be cleaned. :return: A dictionary with the same keys as the input dictionary, but with the "undefined" values removed.