-
Notifications
You must be signed in to change notification settings - Fork 4
E. First step to develop a new module for Lucterios
Prerequisite: To install Lucterios V2 and have an instance created.
In the reste of this tutorial, we call "dev" your working instance and we suppose you want to create the module "foobar"
We are in the Django's world, so a Lucterios module is, in fact, a Django application using Lucterios capabilities
So it's very simple:
python manager_dev.py startapp foobar
Then, you need to add and update this in your foobar/__init__.py
:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
__version__ = "my version number"
__title__ = "my title"
To add this new module in your "dev" instance, use this command:
lucterios_admin.py modif --name dev --module lucterios.contacts,foobar
note1: If you want that foobar either in a sub package (ex mypackage.foobar
) will require manually moved after recreating package mypackage
and its __init__.py
note2: To be assure the multi-language and translation, add this inclusion in your modules:
from django.utils.translation import ugettext_lazy as _
see: https://docs.djangoproject.com/fr/1.9/topics/i18n/translation/
note3: To be compatible to Python 2.x and Python 3.x, we recommend to add in top of each module:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
and to use the module django.utils.six
to convert string value.
see: https://docs.djangoproject.com/en/1.9/topics/python3/
Models are mainly Django's models with some little differences.
First, in lucterios, you need to inherit of lucterios.framework.models.LucteriosModel and not Django's original inheritance
For example, studies the LegalEntity
model of contacts
:
class LegalEntity(AbstractContact):
name = models.CharField(_('name'), max_length=100, blank=False)
structure_type = models.ForeignKey('StructureType', verbose_name=_('structure type'), \
null=True, on_delete=models.SET_NULL)
identify_number = models.CharField(_('identify number'), max_length=100, blank=True)
@classmethod
def get_show_fields(cls):
ident_field = ['name', 'structure_type']
ident_field.extend(super(LegalEntity, cls).get_show_fields())
ident_field.append('identify_number')
res_fields = {_('001@Identity'):ident_field, _('002@Management'):['responsability_set']}
return res_fields
@classmethod
def get_edit_fields(cls):
res_fields = ['name', 'structure_type']
res_fields.extend(super(LegalEntity, cls).get_edit_fields())
res_fields.append('identify_number')
return res_fields
@classmethod
def get_search_fields(cls):
res_fields = ['name', 'structure_type']
res_fields.extend(super(LegalEntity, cls).get_search_fields())
res_fields.extend(['identify_number', 'responsability_set.individual.firstname', \
'responsability_set.individual.lastname', 'responsability_set.functions'])
return res_fields
@classmethod
def get_default_fields(cls):
return ["name", 'tel1', 'tel2', 'email']
@classmethod
def get_print_fields(cls):
return ["name", 'structure_type', 'address', 'postal_code', 'city', 'country', 'tel1', \
'tel2', 'email', 'comment', 'identify_number', 'OUR_DETAIL']
def __str__(self):
return self.name
def can_delete(self):
msg = AbstractContact.can_delete(self)
if msg == '':
if self.id == 1: # pylint: disable=no-member
msg = _("You cannot delete this legal entity!")
return msg
class Meta(object):
# pylint: disable=no-init
verbose_name = _('legal entity')
verbose_name_plural = _('legal entities')
class Responsability(LucteriosModel):
individual = models.ForeignKey(Individual, verbose_name=_('individual'), null=False)
legal_entity = models.ForeignKey(LegalEntity, verbose_name=_('legal entity'), null=False)
functions = models.ManyToManyField(Function, verbose_name=_('functions'), blank=True)
...
Then, to use default form generation, you need to add a few tables:
get_default_fields()
List of fields present in auto generated grid or list.
It's a list
structure.
If not override, this method return list of Django field names.
get_show_fields()
List of fields present in auto generated show form.
Its a dico
structure of list with each key is the label of a new tab in the screen.
The key empty correspond to the header of screen without tab.
If it is a list
, all field will be in header of screen without tab.
In the key, number before '@' sign will be remove: it's user to sort tab.
If you want include many-to-one field, add it '_set' in suffix to the class name lower of this field linked.
If not override, this method return the list returned by get_default_fields().
get_edit_fields()
List of fields present in auto generated edit form.
There are the same syntax that for get_show_fields method.
If not override, this method return the list returned by get_show_fields().
get_search_fields()
List of fields present in auto generated search form.
It's a list
structure.
If not override, this method return the list returned by get_default_fields().
get_print_fields()
List of fields present in report editor for print list or label.
It's a list
structure.
If not override, this method return the list returned by get_default_fields().
Editors are optional module to customize default editors.
For example, studies the LegalEntity
editor of contacts
:
class LegalEntityEditor(AbstractContactEditor):
def edit(self, xfer):
if self.item.id == 1: # pylint: disable=no-member
xfer.remove_component('lbl_structure_type')
xfer.remove_component('structure_type')
return AbstractContactEditor.edit(self, xfer)
def show(self, xfer):
if self.item.id == 1: # pylint: disable=no-member
xfer.remove_component('lbl_structure_type')
xfer.remove_component('structure_type')
return AbstractContactEditor.show(self, xfer)
Some additional functions 'edit', 'show', 'can_delete', 'saving' may be added to customize specific behavior of these editor.
Here is one of the powerfull adds of Lucterios
You will have to add one class by action but, as long as you keep using default forms, you just need a few lines per class.
example:
@ActionsManage.affect('LegalEntity', 'show')
@MenuManage.describ('contacts.change_legalentity')
class LegalEntityShow(XferShowEditor):
caption = _("Show legal entity")
icon = "legalEntity.png"
model = LegalEntity
field_id = 'legal_entity'
@MenuManage.describ('contacts.change_individual', FORMTYPE_NOMODAL, 'contact.actions', _('To find a legal entity following a set of criteria.'))
class LegalEntitySearch(XferSearchEditor):
caption = _("Legal entity search")
icon = "legalEntityFind.png"
model = LegalEntity
field_id = 'legal_entity'
This class and it's decorators is sufficient to add or edit a custom field in an Individual of the contact module.
-
ActionsManage.affect
: To assign the action to an accessible button to view other
=> generic tag used: add, modify, show, edit, del, print, listing, label -
MenuManage.describ
: To set needed right to access (class 'permission' of Django).
Optional parameters using to define this action like menu item (not a menu item if not define):- modal: FORMTYPE_MODAL or FORMTYPE_NOMODAL
- menu_parent: parent's name of the menu item
- menu_desc: test description of the menu item
You should check
lucterios.contacts.views_contacts
to understand the full syntax.
By default, django creates 3 permission by entity model: change, add and delete. The names are made this way:
change_<lower case entity name>
add_<lower case entity name>
delete_<lower case entity name>
To define other permissions, you need to add them the django's way: see django's permissions documentation
In those classes, inheritance is the main aspect:
1 XferListEditor
: To display the registration list of a model
2 XferShowEditor
: To display (read-only) recording of the model
3 XferAddEditor
: To edit (writing) a record of the model. Safeguard action is included in.
4 XferDelete
: To delete a record
5 XferSearchEditor
: To display a record search window
6 XferPrintAction
: To print a 'show' was associated
7 XferPrintListing
: To make a list of print
8 XferPrintLabel
: To make a label printing
9 XferContainerCustom
, XferSave
, XferContainerAcknowledge
..: They are more basic view to make customized screens. 95% of the modules do not have needs (at least, that's my goal)