This document describes how to add a model to openPLM.
Warning
This method is simple and easy if you just want to add one or several models. If you want to add a specific view, see How to add a model (django application).
Note
You should not use your production environment for development purpose. It’s recommanded to initiate a development environment:
- copy openPLM’s directory in another place
- use the settings.py.sqlite as settings file (rename it settings.py)
- run ./manage.py sql all
- run ./manage.py syncdb (this should ask you if you want to create a superuser, accept it)
- edit the superuser profile (model UserProfile in the plmapp section) and set him as an administrator and a contributor
The first step is simple: just add a .py file in openPLM/plmapp/customized_models directory. In this how-to, we will call it bicycle.py. The name of the file must be a valid Python module name.
Now you can edit your file, and add some useful imports:
1 2 3 4 5 6 | from django.db import models
from django.contrib import admin
from openPLM.plmapp.models import Part
from openPLM.plmapp.controllers import PartController
from openPLM.plmapp.utils import get_next_revision
|
First, we import models and admin. We need models to define our models, and we need admin to register our model and make it available on the admin interface.
Next, we import some classes and functions from openPLM.plmapp:
- Part is the base class for models which describe a part;
- PartController is the base class for part’s controller;
- get_next_revision() is an utility function.
After the import, you can add a new class. The name of this class, would be the name displayed in the type field in search/creation pages.
In our case, we call it Bicycle:
1 2 3 4 | class Bicycle(Part):
class Meta:
app_label = "plmapp"
|
As you can see, this class contains another class called Meta. This is a mechanism from Django to customize some model options such as ordering option. Here, we set app_label to "plmapp" so that our model can be managed by Django.
Voir aussi
The Django documentation for Meta options
Now, we can add fields to our models. A field describe which data would be saved in the database.
1 2 3 4 5 6 7 8 9 10 | class Bicycle(Part):
class Meta:
app_label = "plmapp"
# bicycle fields
nb_wheels = models.PositiveIntegerField("Number of wheels", default=lambda: 2)
color = models.CharField(max_length=25, blank=False)
details = models.TextField(blank=False)
|
We add 3 fields:
- nb_wheels
as it says, the number of wheels
This field is a PositiveIntegerField. As first argument, we give a more comprehensive name that would be displayed in the attributes page.
We also set a default value for this field with default=lambda: 2. The default argument does not take a value but a function which does takes no argument and return a value. Here, we use a lambda expression which always returns 2.
- color
the color of the bicycle
This field is a CharField. With a CharField, you must define the max_length argument. This is the maximal number of characters that can be stored in the database for this field.
We also set blank to True, this means that this field can be empty in a form.
- details
a field for quite long details
This field is a TextField. This is a field that is displayed with a textarea in forms.
Voir aussi
The Django model field reference for all types of field that can be used and their arguments
By default, the fields are not displayed. To select which fields should be displayed, you can override the method attributes like in the example above:
1 2 3 4 5 | @property
def attributes(self):
attrs = list(super(Bicycle, self).attributes)
attrs.extend(["nb_wheels", "color", "details"])
return attrs
|
attributes is a read-only property(). This property is a list of attributes, so all elements must be a valid field name. For example, "spam" is not valid since spam is not a field of Bicycle. The property should return attributes from the parent class (Part in our case). That’s why we call super(). In our case, we extends Part attributes with nb_wheels, color and details
There are other methods that can be overridden to select attributes displayed in creation/modification forms.
These methods are listed in PLMObject.
Here, we will excluded details from a creation form:
1 2 3 | @classmethod
def excluded_creation_fields(cls):
return super(Bicycle, cls).excluded_creation_fields() + ["details"]
|
This code is similar to the attributes property. Nevertheless, PLMObject.excluded_creation_fields() is a classmethod() since we do not have a PLMObject when we build a creation form.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Bicycle(Part):
class Meta:
app_label = "plmapp"
# bicycle fields
nb_wheels = models.PositiveIntegerField("Number of wheels", default=lambda: 2)
color = models.CharField(max_length=25, blank=False)
details = models.TextField(blank=False)
# bicycle properties
@property
def attributes(self):
attrs = list(super(Bicycle, self).attributes)
attrs.extend(["nb_wheels", "color", "details"])
return attrs
# excluded_creation_fields
@classmethod
def excluded_creation_fields(cls):
return super(Bicycle, cls).excluded_creation_fields() + ["details"]
# end Bicycle
|
To make our model available on the admin interface, we just have to add this line:
1 | admin.site.register(Bicycle)
|
Now you can test your model. Run the following commands:
- manage.py sql plmapp
- manage.py syncdb
The last command should output:
Installing json fixture 'initial_data' from absolute path.
Installed 10 object(s) from 1 fixture(s)
If there is an error, you will see something like this:
Exception in import_models bicycle <type 'exceptions.AttributeError'> 'module' object has no attribute 'register'
Installing json fixture 'initial_data' from absolute path.
Installed 10 object(s) from 1 fixture(s)
(here, we have written admin.register instead of admin.site.register).
Then you can run the server with the ./manage.py runserver localhost:8000. Open the url http://localhost:8000/home/ and try to create a bicycle.
The model describes only which data should be stored on the database and which attributes should be displayed/editable. You can change how the objects are manipulated by redefining the PLMObjectController of your model.
In this tutorial, we will change the behaviour when a bicycle is revised. Here is the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class BicycleController(PartController):
def revise(self, new_revision):
if new_revision == get_next_revision(get_next_revision(self.revision)):
self.details += """
----------------
hello easter egg
----------------
"""
self.save()
return super(BicycleController, self).revise(new_revision)
# end BicycleController
|
As you can see, we create a class called BicycleController which inherits from PartController. A PartController is a controller which manages some specifities of the parts like their children. Since Bicycle inherits from Part, our controller inherits from PartController. If you name a controller like modelController, it will be associated to the model named model.
In our case, we just override the method PartController.revise() by adding a detail if the user forget a revision (for example, c instead of b). Of course, you can write what you want and, for example, not take care of new_revision.
Voir aussi
mod:controllers and How to add a controller for more details about controllers.
The complete file is accessible here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | from django.db import models
from django.contrib import admin
from openPLM.plmapp.models import Part
from openPLM.plmapp.controllers import PartController
from openPLM.plmapp.utils import get_next_revision
# end of imports
# class Bicycle
class Bicycle(Part):
class Meta:
app_label = "plmapp"
# bicycle fields
nb_wheels = models.PositiveIntegerField("Number of wheels", default=lambda: 2)
color = models.CharField(max_length=25, blank=False)
details = models.TextField(blank=False)
# bicycle properties
@property
def attributes(self):
attrs = list(super(Bicycle, self).attributes)
attrs.extend(["nb_wheels", "color", "details"])
return attrs
# excluded_creation_fields
@classmethod
def excluded_creation_fields(cls):
return super(Bicycle, cls).excluded_creation_fields() + ["details"]
# end Bicycle
admin.site.register(Bicycle)
# class BicycleController
class BicycleController(PartController):
def revise(self, new_revision):
if new_revision == get_next_revision(get_next_revision(self.revision)):
self.details += """
----------------
hello easter egg
----------------
"""
self.save()
return super(BicycleController, self).revise(new_revision)
# end BicycleController
|