Getting started

Django already gives a solid foundation for building apps. Trionyx add some improvements like auto loading signals/forms/cron’s. It also add new things as default views/api/background tasks (celery).

In this getting started guide we will create a new app, to show you a little of the basics on how Trionyx work and what it can do.

This guide assumes you have followed the installation instructions, and you are now in the root of your new project with the virtual environment active

This guide requires no previous knowledge of Django, but it wont go in depth on how Django works

Your first app

First we need to create a new app. Default Trionyx structure all apps go in the apps folder. To create a base app use the following manage command:

./manage.py create_app knowledgebase

In your apps folder should be your new app knowledgebase. For using the app we need to add it the INSTALLED_APPS:

# config/settings/base.py
# ...

INSTALLED_APPS += [
    'apps.knowledgebase',
]

# ...

File structure

A Trionyx file structure looks as follows. The ones marked as bold, are the ones you typically use in a Trionyx app. The others are used with a Django app and can be used if you need more customization.

  • <app name>
    • migrations: DB migrations, these are auto generated by Django
    • static: folder with your static files (js/css/images/icons)
    • templates: HTML template files
    • apps.py: Contains the app and model configuration
    • cron.py: Cron configuration
    • forms.py: Create and register your forms.
    • layouts.py: Create your layouts
    • models.py: Define your models
    • tasks.py: Create your background tasks
    • urls.y: Define your custom urls
    • views.py: Create your custom views

Create model

We need a model to store our articles, this is just a simple Django model. Only difference is that we extend from BaseModel that add some extra Trionyx fields and functions.

# apps/knowledgebase/models.py
from trionyx import models
from django.contrib.contenttypes import fields

class Article(models.BaseModel):

    title = models.CharField(max_length=255)
    content = models.TextField()

    # Generic relation so that different model types can be linked
    # More info: https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#generic-relations
    linked_object_type = models.ForeignKey(
        'contenttypes.ContentType',
        models.SET_NULL,
        blank=True,
        null=True,
    )
    linked_object_id = models.BigIntegerField(blank=True, null=True)
    linked_object = fields.GenericForeignKey('linked_object_type', 'linked_object_id')

After you created the model you need to make a migration (tells the database what to do). And then run the migration to create the database table.

./manage.py makemigrations ./manage.py migrate

If you run your project with make run and you login on it. You will see the menu has a Knowledgebase -> Article entry. You can create/view/edit articles but default list view is only id, and form is not user friendly.

Custom Form

Lets update the create and edit form to only show the title and content. And improve the content form field by using a wysiwyg editor.

# apps/knowledgebase/forms.py
from trionyx import forms
from .models import Article

@forms.register(default_create=True, default_edit=True)
class ArticleForm(forms.ModelForm):
    content = forms.Wysiwyg()

    # We are going to use this later
    linked_object_type = forms.ModelChoiceField(ContentType.objects.all(), required=False, widget=forms.HiddenInput())
    linked_object_id = forms.IntegerField(required=False, widget=forms.HiddenInput())

    class Meta:
        model = Article
        fields = ['title', 'content']

If you refresh your page you should see an improved create form. When you created an article it is rendered with a simple default layout, we are going to change that later. First do some configuration so that there is a better verbose name, one menu item and a better default list view.

Model configuration

You can configure your model in the apps.py, lets change some for Article:

# apps/knowledgebase/apps.py
from trionyx.trionyx.apps import BaseConfig, ModelConfig

class Config(BaseConfig):
    """Knowledgebase configuration"""

    name = 'apps.knowledgebase'
    verbose_name = 'Knowledgebase'

    class Article(ModelConfig):

        # Improve default list view for users
        list_default_fields = ['created_at', 'created_by', 'title']

        # Set a clear verbose name instead of 'Article(1)'
        verbose_name = '{title}'

        # Move menu item to root and set a nice icon
        menu_root = True
        menu_icon = 'fa fa-book'

If you take a look now at the list view it looks much more informative. And the extra submenu is also replaced by only one menu item with a nice icon.

Custom Layout

Lets update the layout to remove some unnecessary fields and add some new ones. Layouts are build with components, so you dont need to write HTML. If you need something custom and dont want to build everything in HTML. There is the trionyx.layout.HtmlTemplate component that renders a given django template and context.

# apps/knowledgebase/layouts.py
from trionyx.views import tabs
from trionyx.layout import Column12, Panel, TableDescription

#register a new tab default this will be `general`
@tabs.register('knowledgebase.article')
def article_layout(obj):
    return Column12(
        Panel(
            obj.title, # For panel the first argument is the title,
            # all other arguments are components
            TableDescription(
                'created_by',
                'created_at',
                'updated_at',
                'content',
            )
        )
    )

This looks nice for your model, lets use that generic field that we created on the model and form. As you can see with the tab register you can create a tab for every model you want. We are going to at a knowledgebase tab to the admin -> users:

# apps/knowledgebase/layouts.py
from trionyx.views import tabs
from trionyx.layout import Column12, Panel, TableDescription, Button, Component, Html
from django.contrib.contenttypes.models import ContentType
from trionyx.urls import model_url

from .models import Article

# ...

@tabs.register('trionyx.user', code='knowledgebase')
def user_layout(obj):
    content_type = ContentType.objects.get_for_model(obj)

    return Column12(
        # Render a create button
        Button(
            'create article',
            url=model_url(Article, 'dialog-create', params={
                'linked_object_type': content_type.id,
                'linked_object_id': obj.id,
            }),
            dialog=True,
            dialog_reload_tab='knowledgebase',
            css_class='btn btn-flat bg-theme btn-block'
        ),
        # Render every article in a new Panel
        *[
            Panel(
                art.title,
                TableDescription(
                    'created_by',
                    'created_at',
                    'updated_at',
                    # Components that accept fields can do so in different formats
                    # Default is string of field name and it will get the label and value

                    {
                        'label': 'Content',
                        'value': Component(
                            Html(art.content),
                            Button(
                                'Edit',
                                url=model_url(art, 'dialog-edit'),
                                dialog=True,
                                dialog_reload_tab='knowledgebase',
                                css_class='btn btn-flat bg-theme btn-block'
                            ),
                        )
                    },
                    object=art,
                )
            ) for art in Article.objects.filter(
                linked_object_type=content_type,
                linked_object_id=obj.id,
            )
        ]
    )

If you reload the page on a user you will see a new tab knowledgebase. Articles that you create here are shown in the tab.

Signals

Django uses signals to allow you to get notifications on certain events from other apps. In this example we are going to use signals on our own Model to send an email to all users when a new article is created.

# apps/knowledgebase/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from trionyx.trionyx.models import User
from .models import Article

@receiver(post_save, sender=Article)
def notify_users(sender, instance, created=False, **kwargs):
    if created:
        for user in User.objects.all():
            user.send_email(
                subject=f"New Article: {instance.title}",
                body=instance.content,
            )

You can find more information about signals here, Only thing that Trionyx does is auto import signals.py from all apps.

Background Task

Trionyx uses celery for background tasks, it comes preconfigured with 3 queue’s. For more information go here. For our app we are going to use a schedulad background task to send a summary every week.

# apps/knowledgebase/tasks.py
from trionyx.tasks import shared_task
from django.utils import timezone
from trionyx.trionyx.models import User
from .models import Article

@shared_task()
def email_summary():
    count = Article.objects.filter(created_at__gt=timezone.now() - timezone.timedelta(days=7)).count()
    for user in User.objects.all():
        user.send_email(
            subject=f"There are {count} new articles",
            body=f"There are {count} new articles",
        )

To make this task run every week we need to add it to the cron. You can do this from inside your app by creating a cron.py.

# apps/knowledgebase/cron.py
from celery.schedules import crontab

schedule = {
    'article-summary-every-sunday': {
        'task': 'apps.knowledgebase.tasks.email_summary',
        'schedule': crontab(minute=0, hour=0, day_of_week=0)
    },
}

Now email_summary will be run every sunday. For more information on scheduling go here

API

If you go to http://localhost:8000/api/ you can see that Trionyx automatically created an API entry point. Trionyx make use of the Django REST framework you can easily create your own endpoint or change the serializer user by the generated end point.

# apps/knowledgebase/serializers.py or apps/knowledgebase/api/serializers.py
from trionyx.api import serializers
from trionyx.trionyx.models import User
from .models import Article

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']

@serializers.register
class UserSerializer(serializers.ModelSerializer):
    created_by = UserSerializer()

    class Meta:
        model = Article
        fields = ['created_by', 'title', 'content']

I hope you have a better understanding on how to use Trionyx. And that it can help you build you business application with the focus on your data and processes.