Attention
This library is in very early stages. Like the idea of it? Please star us on GitHub and contribute via the issues board and the twined roadmap.
Django Twined¶
django-twined helps run data services based on the twined framework from your own django server.
If you’re a scientist or engineer getting started with creating online data services, here is definitely NOT the right place to start! Check out the documentation for twined and the example app templates in the SDK.
“Twined” [t-why-nd] ~ encircled, twisted together, interwoven
Aims¶
This is an installable app for django, that allows management of octue-based services from django.
- This is great for advanced use cases where:
you have specific security/firewalling requirements, or
you want to manage your own auth, or
you have specific/unusual data integration needs, or
you have a pre-existing django-based web app and want to connect it into the twined ecosystem
you want to run your apps on a cluster, and provide a single entrypoint for external services to connect
Health warning: to use this plugin to deploy your twined apps, you’ll need to handle all your own data storage/orchestration, devops, server management, security and auth. Contact Octue if this doesn’t sound like your bag - we can help!
Contents¶
Installation¶
Install the library¶
django-twined is available on pypi, so installation into your python virtual environment is dead simple:
poetry add django-twined
Not using poetry yet? You definitely should, there’s a small learning curve then it removes a world of pip agony :)
Install the django app¶
You’ll need to install django_twined
, django_gcp
and jsoneditor
as apps in your django settings:
INSTALLED_APPS = [
# ...
'django_gcp', # For event handlers and flexible storages
'django_twined',
'jsoneditor', # For editing JSON in modeladmin views
# ...
]
Tip
You can use django-gcp for your media/static storage, event handlers and task queues too!
Add the services endpoint¶
Include the django-twined URLs in your your_app/urls.py
:
from django.urls import include, re_path
urlpatterns = [
# ...other routes
# Use whatever regex you want:
re_path(r"^integrations/octue/", include("django_twined.urls")),
]
Using python manage.py show_urls
you can now see the endpoint for registering and getting service revisions appear in your app.
Warning
The registry URLs are CSRF-exempt by default to allow automatic service revision registration from, for example,
GitHub Actions. If you don’t want this behaviour, you can import the view at django_twined.views.service_revision
and use it in your URL patterns as you like.
Run migrations¶
Then run python manage.py migrate django_twined
to add the models used for managing services, events and questions to your database.
Add the base URL¶
Finally, make sure the BASE_URL
setting is present in settings.py
- it’s used to create absolute URLs for webhooks.
BASE_URL = "https://your-server.com"
Quick Start¶
Attention
LIBRARY IS UNSTABLE! WATCH THIS SPACE!
We suggest at this point you don’t try to use this yourself; contact Octue for support and we’ll help you out.
Running a service registry¶
Once the services endpoint has been added, your app can be used as a service registry - ie service revisions can be registered and requested from it.
Registering a service revision¶
To register a service revision:
import requests
response = requests.post(
"<base_url>/<chosen_path_for_django_twined_urls>/services/<namespace>/<name>",
json={"revision_tag": "<revision_tag>"},
)
For example, if your base URL is myapp.org/api
, you’ve registered the django-twined
URLs under
integrations/octue
, and the service revision you want to register is my-org/my-service:1.2.9
, the request would
be:
import requests
response = requests.post(
"https://myapp.org/api/integrations/octue/services/my-org/my-service",
json={"revision_tag": "1.2.9"},
)
Tip
To override the registry deciding if the service revision being registered should be set as the default (see below),
add the "is_default"
key to the request body and set it to either True
or False
.
Getting the default service revision¶
You can request the default service revision by not specifying a revision tag. By default, the service revision with the latest semantic version revision tag will be returned.
import requests
response = requests.get(
"https://myapp.org/api/integrations/octue/services/my-org/my-service",
)
response.json()
>>> {
"namespace": "my-org",
"name": "my-service",
"revision_tag": "1.2.9",
"is_default": True,
}
Tip
If you know the exact revision you want to use, you can still fetch further information for it.
import requests
response = requests.get(
"https://myapp.org/api/integrations/octue/services/my-org/my-service"
"?revision_tag=1.2.9",
)
response.json()
>>> {
"namespace": "my-org",
"name": "my-service",
"revision_tag": "1.2.9",
"is_default": True,
}
Currently, the only useful information this provides is whether the requested service revision is the default or not. Later, more useful information will be returned (eg how to send a question to that specific service revision and access tokens to do so).
Controlling whether a service revision is set as the default at registration¶
The TWINED_SERVICE_REVISION_IS_DEFAULT_CALLBACK
setting can be set to a user-defined callable to control whether a
service revision is set as the default for its service during registration. The callable must take one argument,
service_revision
(an instance of the ServiceRevision
model), and return a boolean indicating whether the
revision should be set as the default. The default callable sets the service revision as the default if its revision
tag is the latest semantic version for the service.
Examples of how this feature can be used include:
A/B testing
Controlling the availability of beta versions of services
Other custom selection of service revisions
Click here to see the default callable as an example.
Settings¶
Name |
Type |
Description |
---|---|---|
|
str |
The server address for generating absolute webhook URLs, eg |
|
str |
The namespace used by default (if none specified) when creating Service Revisions. Typically your organisation, and should be in kebab case, eg |
|
str |
The GCP project name used by default (if none specified) when creating Service Revisions. This is the project where the default-namespace services reside. Often (but not necessarily), this is the same as the namespace eg |
|
str |
The tag used by default (if none specified) when creating new Service Revisions. |
|
dict |
DEPRECATED - DO NOT USE. The |
|
dict |
A dictionary defining one or more Data Stores, which map a database table (django Model) to a bucket on GCP, syncing metadata between the files in the bucket and filterable / searchable columns in teh DB table. |
|
callable |
A function that takes one argument, |
Examples¶
Here, we look at example use cases for the library, and show how to use it in python.
It’s also well worth looking at the unit test cases.
Tabs with different examples¶
You need to provide stuff
We need tabs!
{
"thats": "right",
"code": "goes in tabs too",
}
License¶
The Boring Bit¶
Third Party Libraries¶
django-twined includes or is linked against code from third party libraries, see our attributions page.
Version History¶
Origins¶
django-twined is the result of a refactor - Octue is progressively open-sourcing our stack for managing and connecting digital twins and data services.
As you do when you’re a bootstrapped startup, we build our MVP as a massive monolithic django app, but wanted to reuse parts of it in applications for clients. Copying/pasting code never makes sense, so here we are!
A huge thank you to Wind Pioneers whose business made the initial refactor possible, and who now get to use twined to build the most kick-ass Wind Energy Resource Assessment applications in the world!
..ATTENTION:
**django-twined** will be unstable in 0.x versions. Consider every semiver increment to be breaking!
Releases¶
We create release notes automatically using our conventional commits tools for completely automating code versions, release numbering and release history.
So for a full version history, check our releases page.