Table Of Contents

Previous topic

2. List of how-to’s

Next topic

2.2. How to add a model (django application)

This Page

Languages

Previous versions

1.2
1.1

2.1. How to add a model (single file)

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:

  1. copy openPLM’s directory in another place
  2. use the settings.py.sqlite as settings file (rename it settings.py)
  3. run ./manage.py sql all
  4. run ./manage.py syncdb (this should ask you if you want to create a superuser, accept it)
  5. edit the superuser profile (model UserProfile in the plmapp section) and set him as an administrator and a contributor

2.1.1. Requirements

  • Python
  • Django models

2.1.2. Add a file

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.

2.1.3. Imports

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:

2.1.4. First class

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.

See also

The Django documentation for Meta options

2.1.5. Custom fields

2.1.5.1. Adding fields

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.

See also

The Django model field reference for all types of field that can be used and their arguments

2.1.5.2. Selecting which fields should be displayed

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

2.1.5.3. Other methods that can be overridden

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.

2.1.6. The complete class Bicycle

 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

2.1.7. The admin interface

To make our model available on the admin interface, we just have to add this line:

1
admin.site.register(Bicycle)

2.1.8. syncdb

Now you can test your model. Run the following commands:

  1. manage.py sql plmapp
  2. 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.

2.1.9. Controller

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.

See also

mod:controllers and How to add a controller for more details about controllers.

2.1.10. Alltogether

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