Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 09:16
· 16 commits to main since this release
1d5b771

Added

  • redirect_field_name on SpecFormView, SpecFormSetView and
    SpecConfirmView: a page returns where it was opened from.
    None by
    default, which reads nothing. Named - "next", as Django's LoginView
    names it - the URL the post or its query carries under that key is read as
    LoginView reads it, the post's value first, and used only where
    url_has_allowed_host_and_scheme allows it against the request's own host,
    with https required on a secure request. A success redirects there in
    place of get_success_url(result), an override included, and under htmx
    answers HX-Redirect to it; a spec-result fragment still answers in
    place. An unsafe URL is ignored, and the success goes where it went before.
    get_redirect_url() answers the safe URL, or "".
    • It survives a refused post. The context carries
      redirect_field_name and next, the safe URL, and the shipped
      templates post them back as a hidden input; neither key is there without
      a safe URL. The key is never an argument: a form page's arguments are its
      fields and its route, and the confirmation page reads nothing posted.
    • as_view() refuses a name that is not a non-empty string, one that is
      the commit_button, on SpecFormView one the form declares as a field,
      and on SpecFormSetView one that is the add_button or sits under the
      formset's form- prefix.
  • refusal_redirect on SpecConfirmView: a refusal sent back to the page
    the button was posted from.
    False by default. Set, an invalid, failed or
    needs-input refusal sends each message the page would show in errors
    through messages.error, with the refusal's code as extra_tags where it
    has one, and redirects to get_refusal_url(refused): the safe URL
    redirect_field_name reads, else success_url. Under htmx it answers
    HX-Redirect. A denial is raised as before. Without the messages middleware
    Django raises MessageFailure, and the page is rendered as it is without
    refusal_redirect, so the refusal is never lost; a refusal with no message
    to send is the page again too. A refusal sent back counts and presents no
    target. as_view() refuses it on a
    page with no success_url that does not override get_refusal_url.
  • The unavailable template filter: why a row's action is unavailable.
    {% with why=row|unavailable:"withdraw" %}{% if why %}{{ why.reason }}{% endif %}{% endwith %}
    returns the row's answer, with the code and reason of the first
    condition the row does not meet, when the action is unavailable, and
    None when it is available. It reads the answers available reads, so it
    costs no query, and raises the same TemplateSyntaxError for a name the
    spec does not declare or a row the page did not serve. A condition on the
    row asked of a row that no longer exists answers with no code and no
    reason, so {% if why %} holds and {{ why.reason }} renders empty. The
    answer is a fresh dict per read, so json_script takes it, whose clear
    and popitem are marked alters_data, so no template can empty it. The
    example's table shows the reason where a row has no Withdraw button.
    • The docs read a negated or combined condition through {% with %},
      for both filters, where they said to use available only as a bare
      {% if %} condition: Django's {% if %} reads an error inside not,
      and, or or a comparison as the condition being false, so a misspelt
      name there draws nothing and raises nothing, and
      {% with ok=row|available:"withdraw" %}{% if not ok %} resolves the filter
      outside {% if %}, where a misspelt name raises.
  • SpecSelectorView.get_query(request), the query string a page reads.
    It answers request.GET unless a subclass answers another QueryDict, and
    the page asks it once a request. On a list page the paging keys, the filter
    form, the spec's arguments and the previous and next links all read its
    answer; an instance page, which is not paged, reads the spec's arguments
    from it. The template is handed a request whose GET is that answer, so a
    django-tables2 table's header sort links keep it. A list that opens where
    the last visit left it answers a query kept in the session on a bare visit;
    the selector guide shows one, with a ?reset=1 that forgets a saved query
    the spec refuses. Like every request hook it is a plain def, and
    as_view() refuses an async def one; an answer that is not a QueryDict
    raises TypeError naming the hook.

Changed

  • The htmx handler example answers an anonymous visitor with the login page
    whether or not htmx asked, and gains a handler404.
    Without htmx, a
    visitor who is not signed in is redirected to the login page and back to the
    page they asked for, where the 403 page used to be shown; a signed-in
    visitor still gets Django's 403 page. The new handler404 answers an htmx
    request with HX-Refresh, since htmx swaps no 4xx body and a stale row's
    action would otherwise do nothing visible, and a browser with Django's 404
    page. The pages state that the same handlers answer a list row's and a
    confirmation's denial, and that the sync pages serve under ASGI, with the
    reason there is no async page.
  • SpecSelectorView ignores a query key its spec does not declare.
    unknown_arguments defaults to UnknownArguments.IGNORE on the list and
    instance pages, so ?utm_source=x, or a bookmark from before a filter was
    renamed, is answered 200 with the rows the rest of the query selects, where
    it was a 400 with utm_source: Unknown argument. A declared key's value is
    read and refused as before, a route kwarg the spec does not declare is
    still the host's misconfiguration, and the JSON views still refuse an
    undeclared key. The form, formset and confirmation pages keep REJECT for
    what they dispatch, their form's fields and the route. Set
    unknown_arguments = UnknownArguments.REJECT on a list whose query only
    code builds to keep the refusal. A list page and a JSON list now read each
    value of one query string the same way, rather than answering it the same.