Skip to main content

Provide model integrity between requests

Project description

nango

Streamlining Django forms to provide all the wins of single-page-applications without the pain.

Key features

Available now:

  • django forms no longer silently overwrite changes made in parallel by other users

Coming soon:

  • django forms can receive push notifications from the server (via Channels) when data used on the form changes, rather than only discovering data is out-of-date when the form is submitted
  • django forms can send provisional form data to the server, allowing server-based field validation before the form is submitted
  • django forms can save form data as it is edited, without needing a "submit" button.

what does this do?

Out of the box, Django provides reasonable support for database-level data consistency while a request is being processed, thanks to transactions. However, it is let down by not providing an easy way to avoid data corruptions between requests.

A simple example, where two users edit the same customer using the admin panel.

https://user-images.githubusercontent.com/236562/148663962-8f343216-cced-41fc-b2c0-c99ccda524e2.mp4

https://user-images.githubusercontent.com/236562/148663959-a0b69f19-c91d-405d-a4cc-1316a24c4bb8.mp4

As you can see, using the normal django tooling, the change made by the first user is lost. This occurs because Django does not track the original form value, making it impossible for it to know that the data was modified between when the form was rendered, and when the form was submitted.

Does this matter to me?

Here's a simple checklist to help you consider if this is a problem for you.

  • Can the same model be edited on multiple forms?
  • Can the same form be accessed simultaneously by multiple people?
  • Can one user access the same form in multiple tabs/windows, either on the same or different devices?

If the data you're storing is not important, maybe you can get away without caring about these "edge cases". However, if they do occur, you will have lost user data. There will be no errors, just users complaining that the changes they made were not saved. The original data will be irretrievable, and it will be difficult to even work out how often it is occurring.

Installation

pip install nango

Configuration

Update views.py (if using generic model views)

Instead of using Django's generic views, replace them with nango's. You can safely just update the import statements with nango. The appropriate views (e.g. UpdateView) will be modified, ensuring they use an "enhanced" form class, and the other views will also be available, unmodified.

from django.urls import reverse_lazy
from nango.views.generic import ListView
from nango.views.generic import edit

from .models import Customer


class IndexView(ListView):
    template_name = "demo/index.html"
    context_object_name = "customers"

    def get_queryset(self):
        return Customer.objects.all()


class UpdateView(edit.UpdateView):
    model = Customer
    fields = ["name", "notes", "company"]
    prefix = "foo"

    def get_form(self):
        return super().get_form()

    def get_success_url(self):
        # return reverse_lazy("demo:edit", kwargs={"pk": self.object.id})
        return reverse_lazy("demo:index")
...

Update forms.py (if explicitly creating forms)

Any forms you are making yourself will need a mixin added to it. You can either do this by explicitly adding the mixin, or modifying the import of the Model base class.

from django.forms import Form
from nango.forms import FormMixin

class MyForm(FormMixin, Form):
    ...
from nango.forms import Form

class MyForm(Form):
    ...

Update models.py

To make a model nango-aware, it will need a mixin added to it. You can either do this by explicitly adding the mixin, or modifying the import of the Model base class. If you choose the first option, you will also need to explicitly mark this class as not abstract, as shown below:

from django.db import models
from nango.db.models import TrackableMixin
class Customer(TrackableMixin, models.Model):
    class Meta:
        abstract = False
        ...
    ...
from nango.db import models

class Customer(models.Model):
    ...

Django may prompt you to create migrations. If so, rest assured that these migrations will not actually modify anything in your database; they are only needed as the model methods are different.

Register the nango application

In your settings.py:

...
INSTALLED_APPS = [
    "nango.apps.NangoConfig",
    "django.contrib.admin",
    ...
    ]
...

Update admin.py

Simply change your django.contrib imports to nango.contrib. The rest of the module can be left unchanged. e.g.

from nango.contrib import admin
from nango.contrib.admin import ModelAdmin
from nango.contrib.admin import register
from nango.contrib.admin import TabularInline

from .models import Company
from .models import Customer


class CustomerInline(TabularInline):
    model = Customer


@admin.register(Company)
class CompanyAdmin(ModelAdmin):
    inlines = [CustomerInline]


admin.site.register(Customer)

OK, so what is actually happening now I've enabled nango?

  1. Whenever a form is rendered (including formsets), either in the admin panel or via a ModelForm, the HTML will include additional hidden input elements. These will ensure that when the form is POSTed, the server will not only be provided with the new field values, but also the original values.
  2. When a form is POSTed, if the additional hidden items are present, these are provided to the associated model instance, prior to other form processing.
  3. Nango's model mixin will provide additional checks, ensuring that the database currently holds the original values contained in the form. (By using select_for_update, we effectively lock these records in the database while performing this check, for the duration of the request).
  4. If clean() fails, appropriate messages will be shown to the user, via the normal mechanism.

Project details


Download files

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

Source Distribution

nango-0.0.15.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nango-0.0.15-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file nango-0.0.15.tar.gz.

File metadata

  • Download URL: nango-0.0.15.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for nango-0.0.15.tar.gz
Algorithm Hash digest
SHA256 6d831bb4640091a61218a13e2ed861f41d4ea4fc9945b8b77c1ffbb6bbd2d66b
MD5 99967a5f2496b278b713bc47e27faea8
BLAKE2b-256 92427240aa53e7c25e36b7d4936c5cc91d0f679f3f641fc6313ae2308d3a6e86

See more details on using hashes here.

File details

Details for the file nango-0.0.15-py3-none-any.whl.

File metadata

  • Download URL: nango-0.0.15-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for nango-0.0.15-py3-none-any.whl
Algorithm Hash digest
SHA256 6f0816287435aa8c19e3274fd39bd1b7462ab8c42a89eed44af1200bc92dc55a
MD5 596cc5697ecf9956c24a81d49218c148
BLAKE2b-256 093374c9d7072d57afaa37da6e1f4129f5224af661fb45f5f81cb75bd69b9dc1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page