rustango 0.38.0

Django-shaped batteries-included web framework for Rust: ORM + migrations + auto-admin + multi-tenancy + audit log + auth (sessions, JWT, OAuth2/OIDC, HMAC) + APIs (ViewSet, OpenAPI auto-derive, JSON:API) + jobs (in-mem + Postgres) + email + media (S3 / R2 / B2 / MinIO + presigned uploads + collections + tags) + production middleware (CSRF, CSP, rate-limiting, compression, idempotency, etc.).
Documentation
{% extends "base.html" %}
{% block title %}{{ model.name }} — rustango admin{% endblock title %}
{% block body %}
<nav class="breadcrumb" aria-label="breadcrumb">
  <ol>
    <li><a href="{{ admin_prefix }}/">{{ admin_title }}</a></li>
    <li><strong>{{ model.name }}</strong></li>
  </ol>
</nav>
<h1>{{ model.name }}</h1>
<div class="list-shell">
<div class="list-main">
<p>Table: <code>{{ model.table }}</code>
{% if count_skipped %}
  &mdash; <em>row count hidden (large table)</em>
{% else %}
  &mdash; {{ total }} row{{ plural }}
{% endif %}
{% if read_only %}
  &nbsp;&middot;&nbsp; <em>read-only</em>
{% else %}
  &nbsp;&middot;&nbsp; <a href="{{ admin_prefix }}/{{ model.table }}/new">+ new {{ model.name }}</a>
{% endif %}
</p>

{% if has_searchable %}
<form method="get" action="{{ admin_prefix }}/{{ model.table }}" class="search">
  <input type="search" name="q" value="{{ q }}" placeholder="Search&hellip;">
  <button type="submit">Go</button>
  {% for f in active_filters %}
    <input type="hidden" name="{{ f.key }}" value="{{ f.value }}">
  {% endfor %}
</form>
{% endif %}

{% if q or active_filters | length > 0 %}
<p class="active-filters">filtered by:
  {% if q %}<code>q={{ q }}</code> {% endif %}
  {% for f in active_filters %}<code>{{ f.key }}={{ f.value }}</code> {% endfor %}
  &middot; <a href="/{{ model.table }}">clear</a>
</p>
{% endif %}

{% if rows | length == 0 %}
<p><em>No rows on this page.</em></p>
{% else %}
<form method="post" action="/{{ model.table }}/__action" class="list-form">
  {% if actions and actions | length > 0 and not read_only %}
  <div class="action-bar">
    <label>Action:
      <select name="action">
        <option value="">— Select —</option>
        {% for a in actions %}
        <option value="{{ a.name }}">{{ a.label }}</option>
        {% endfor %}
      </select>
    </label>
    <button type="submit">Go</button>
  </div>
  {% endif %}
  <table>
    <thead>
      <tr>
      {% if actions and actions | length > 0 and not read_only %}
        <th class="checkbox-col"></th>
      {% endif %}
      {% for col in columns %}
        <th>{{ col.label | safe }}</th>
      {% endfor %}
        <th></th>
      </tr>
    </thead>
    <tbody>
    {% for row in rows %}
      <tr>
        {% if actions and actions | length > 0 and not read_only %}
        <td class="checkbox-col">{% if row.pk %}<input type="checkbox" name="_selected" value="{{ row.pk }}">{% endif %}</td>
        {% endif %}
        {% for cell in row.cells %}<td>{{ cell | safe }}</td>{% endfor %}
        <td>{% if row.pk %}<a href="{{ admin_prefix }}/{{ model.table }}/{{ row.pk }}">View</a>{% endif %}</td>
      </tr>
    {% endfor %}
    </tbody>
  </table>
</form>
{% endif %}

{% if count_skipped %}
<p class="pager">
  {% if page > 1 %}
    <a href="{{ admin_prefix }}/{{ model.table }}?page={{ page - 1 }}{{ pager_suffix | safe }}">&larr; prev</a>
  {% else %}
    <span class="muted">&larr; prev</span>
  {% endif %}
  &middot; Page {{ page }} &middot;
  {% if has_next %}
    <a href="{{ admin_prefix }}/{{ model.table }}?page={{ page + 1 }}{{ pager_suffix | safe }}">next &rarr;</a>
  {% else %}
    <span class="muted">next &rarr;</span>
  {% endif %}
</p>
{% elif last_page > 1 %}
<p class="pager">
  {% if page > 1 %}
    <a href="{{ admin_prefix }}/{{ model.table }}?page={{ page - 1 }}{{ pager_suffix | safe }}">&larr; prev</a>
  {% else %}
    <span class="muted">&larr; prev</span>
  {% endif %}
  &middot; Page {{ page }} of {{ last_page }} &middot;
  {% if page < last_page %}
    <a href="{{ admin_prefix }}/{{ model.table }}?page={{ page + 1 }}{{ pager_suffix | safe }}">next &rarr;</a>
  {% else %}
    <span class="muted">next &rarr;</span>
  {% endif %}
</p>
{% endif %}
</div>{# /list-main #}
{% if facets and facets | length > 0 %}
<aside class="list-rail">
  {% for facet in facets %}
  <section class="facet">
    <h4>By {{ facet.field }}</h4>
    {% if facet.is_fk %}
    {# FK facets: dropdown so the operator picks from named options #}
    <select onchange="location.href=this.options[this.selectedIndex].dataset.href" style="width:100%;margin-bottom:.4rem">
      <option data-href="{{ facet.clear_url | safe }}">— all —</option>
      {% for v in facet.values %}
      <option data-href="{{ v.toggle_url | safe }}"{% if v.active %} selected{% endif %}>{{ v.display | safe }} ({{ v.count }})</option>
      {% endfor %}
    </select>
    {% else %}
    {# Non-FK facets: link list (original behaviour) #}
    <ul>
    {% for v in facet.values %}
      <li>
        <a href="{{ v.toggle_url | safe }}"{% if v.active %} class="active"{% endif %}>{{ v.display | safe }}</a>
        <span class="count">({{ v.count }})</span>
      </li>
    {% endfor %}
    {% if facet.more_count and facet.more_count > 0 %}
      <li class="facet-more"><a href="{{ facet.show_all_url | safe }}">+{{ facet.more_count }} more&hellip;</a></li>
    {% endif %}
    </ul>
    {% endif %}
  </section>
  {% endfor %}
</aside>
{% endif %}
</div>{# /list-shell #}
{% endblock body %}