🇪🇦 Leer en Español, “GenCreate, GenDetail, GenUpdate y GenDelete

In the last article, we described GenList to start using CODENERIX listings. The time has come to see how to create, view, update and delete the information on those listings.

In this article, we will talk about GenCreate, GenDetail, GenUpdate, and GenDelete.

First, each one inherits from its Django equivalent, such that GenCreate inherits from CreateView, GenUpdate from UpdateView, GenDetail from DetailView, and GenDelete from DeleteView.

Let’s see first what the example model that we are going to use, “Contact“, would look like:

class Contact(CodenerixModel):
    first_name = models.CharField(verbose_name=_(u'Name(s)'), max_length=128)
    last_name = models.CharField(verbose_name=_(u'Last name'), max_length=128, blank=True, null=True)
    alias = models.CharField(verbose_name=_(u'Alias'), max_length=32, blank=True, null=True)
    organization = models.CharField(verbose_name=_(u'Organization'), max_length=64, blank=True, null=True)
    borndate = models.DateField(verbose_name=_(u'Borndate'), blank=True, null=True)
    address = models.TextField(verbose_name=_(u'Address'), blank=True, null=True)
    created_by = models.ForeignKey(User, verbose_name=_(u'Created by'), on_delete=models.CASCADE, related_name='contacts')

    def __fields__(self, info):
        return (
            ('first_name', _(u'Name(s)')),
            ('last_name', _(u'Last name')),
            ('alias', _(u'Alias')),
            ('organization', _(u'Organization')),
        )

and your “ContactForm” form, which will inherit from GenModelForm.

GenModelForm:

from codenerix.forms import GenModelForm

class ContactForm(GenModelForm):

    class Meta:
        model = Contact
        exclude = ['created_by']

    def __groups__(self):
        return [
            (
                _(u'Principal'), 6,
                ['first_name', 6],
                ['last_name', 6],
                ['alias', 6],
            ),
            (
                _(u'Principal'), 6,
                ['organization', 6],
                ['borndate', 6],
                ['address', 6],
            )
        ]

    @staticmethod
    def __groups_details__():
        return [
            (
                _(Contact'), 12,
                ['alias', 12],
                ['organization', 12],
                ['borndate', 12],
                ['address', 12],
            )
        ]

Since GenModelForm is new, I will only point out that it inherits from Django‘s BaseModelForm and that the only thing new compared to a Django ModelForm is the groups. Groups are the definition of how we want a form to look on the screen and are built with a list of tuples containing:

  1. Field block title
  2. Width in Bootstrap columns
  3. N-tuples refer to the fields of the form where each tuple will have as its first element the name of the field that will go in that position and its width in Bootstrap columns. There are more elements in these tuples that I will explain in future posts.

In this way, the form indicated above would be as follows:

Where the fields are self-validated on the user’s browser side and thus greatly reduce server calls. Said form explained to your group would be as follows:

Let’s discover the details of these 4 views that work like their Python counterparts with the same attributes and methods as these but offer much more functionality.

GenModify

To talk to GenCreate and GenUpdate, we first have to talk about GenModify, which manages the operation when a record is created and updated. It is not a view that we will use directly. However, this class will indirectly be part of GenCreate and GenUpdate, respectively. Since the creation and update of the record vary in minimal matters: the form coincides, and the validations are the same, the GenModify class is in charge of managing how GenCreate and GenUpdate act in each case, preloading the form with the record that is being edited in a GenUpdate and both cases storing the changes (new or updated) in the database.

Table of attributes allowed by GenModify

AttributeDescription
angular_deleteName of the angular method that will receive the action when the “Delete” button is pressed, by default “delete”.

angular_delete = "delete"
angular_submitName of the angular method that will receive the action when the form is submitted, by default, “submit”.

angular_submit = "submit"
buttons_bottomShow action buttons below the form, and defaults to True.

buttons_bottom = True
buttons_topIt shows the action buttons above the form and defaults to True.

buttons_bottom = True
extends_baseIt contains the base template path from which the List template will inherit. It usually goes to a “base/base.html“, but by changing this variable, you can tell it to load a different file to offer the user a different environment experience.

extends_base = "base/base.html"
form_groupsThe group to apply to this view (equivalent to __groups__) can be a method or a function.
form_ngcontrollerBy specifying this attribute, an extra controller will be added to the form that will serve to include extra functionalities accessory to the standard form.

form_ngcontroller = "nuevo_controlador"
__groups__The group to apply to this view (equivalent to form_groups) can be a method or a function.
hide_foreignkey_buttonWhen this attribute is activated, the option to work the fields with external relationships through modal windows is shown. By default this attribute is False. In the following example, you can see 2 fields, “Brand” (Marca) and “Category” (Categoría), in which since there is no element selected in “Brand”, the system shows a “+” symbol to add a new record since it assumes that none of those in the list is valid for the user to fill in that field. If there is a selected element, the system displays a “pencil” in order to allow the selected element to be edited. Both “creation” and “editing” occur in a modal window.



Sometimes we do not want to see these buttons because we do not want the user to access these modal windows, either because we do not want them visually or because they do not have permissions or they are not developed. Marking this attribute as “True” will hide these buttons.

hide_foreignkey_button = False
jsonIt will return a response in JSON format, by default, True.

json = True
json_detailsIt will trigger verbose responses in JSON responses, by default, True.

json_details = True
linkbackIt shows the “Back” button and defaults to True.

linkback = True
linkdeleteIt shows the “Delete” button and defaults to True. This attribute is only available in editing forms (it is not enabled for creation forms since there is no record to delete).

linkdelete = True
linksavehereIt shows the “Save Here” button, which defaults to True.

linksavehere = True
linksavenewIt shows the “Save and New” button, which defaults to True.

linksavenew = True
show_detailsAt the end of the execution of the form, the system will try to return to the list, however, if show_details is activated, the system will go to the details view instead of the list.

show_details = True
show_internal_nameWhen set to True, it will display a title on the form. By default, it is activated in normal forms and deactivated in “modal” forms.

show_internal_name = True
success_url_keysA correctly completed form always responds with a valid status and also with a JSON dictionary containing at least 2 keys:
  • __pk__ which includes the PK of the created or updated object__str__ that contains the representation in text format of said created or updated object.
The response system always overwrites these 2 keys. However, if other keys are included in the success_url_keys attribute, they will also be included in the form response, and this data can be used to obtain extra information on the object created/modified or on its status. end of the operation requested to the form.

The success_url_keys attribute should be a list of strings that can have the following format:
  • “key”: will be evaluated as if it were “key:key”“key1:key2”: will be evaluated as answer[key1]=object.key2

success_url_keys = ["id","name:title"]
titleIf show_internal_name is activated, a title will be shown, and the title will be calculated automatically by mixing the action, which can be “Adding” or “Editing”, and the form’s name. However, when modifying this attribute, the content of this attribute will be displayed directly, preventing it from being auto-calculated.

title = _("Nuevo título para el formulario")

These attributes are available in both the create and edit views.

GenCreate and GenCreateModal

from codenerix.views import GenCreate, GenCreateModal
class ContactCreate(GenCreate):
    model = Contact
    form_class = ConctactForm
class ContactCreateModal(GenCreateModal, ContactCreate):
    pass

GenCreate is a view that inherits Django‘s CreateView from GenModify. At its minimum, it needs the same fields as CreateView. These are “model” and “form_class“. Since GenCreate inherits from GenModify, its features will also be available.

To the views to which we include a GenCreateModal, we will get the render to prepare the result to be displayed in a modal window. In the background, what actually happens is that it adds the Bootstrap modal window marquee and ends the rendering at that point.

GenUpdate and GenUpdateModal

from codenerix.views import GenUpdate, GenUpdateModal
class ContactUpdate(GenUpdate):
    model = Contact
    form_class = ContactForm
class ContactUpdateModal(GenUpdateModal, ContactUpdate):
    pass

GenUpdate is a view that inherits Django‘s UpdateView from GenModify. At its minimum, it needs the same fields as UpdateView. These are “model” and “form_class“. Since GenUpdate inherits from GenModify, GenModify‘s features will also be available.

In the views to which we include a GenUpdateModal, we will get the render to prepare the result to be displayed in a modal window. In the background, what actually happens is that it adds the Bootstrap modal window marquee and ends the rendering at that point.

GenDetail and GenDetailModal

from codenerix.views import GenDetail, GenDetailModal
class ContactDetail(GenDetail):
    model = Contact
    groups = ContactForm.__groups_details__()
class ContactDetailModal(GenDetailModal, ContactDetail):
    pass

GenDetail is a view that inherits Django‘s DetailView and GenModify, used to display data from an object. At its minimum, it needs the same fields as the DetailView. These are “model” and “form_class“.

To the views to which we include a GenDetailModal, we will get the render to prepare the result to be displayed in a modal window. In the background, what actually happens is that it adds the Bootstrap modal window marquee and ends the rendering at that point.

Table of attributes allowed by GenDetail

AttributeDescription
exclude_fieldsA list of fields will be excluded when rendering the object’s data. GenDetail will always show all the fields of the object, it will use (just like forms) the groups to show the information organized by them, and the rest of the fields will go consecutively at the end of the group. However, if a field appears in the exclude_fields list, it will not be displayed in the details view.

exclude_fields = ["contact", "price"]
extra_contextIt is a dictionary that contains extra information that will be sent to the template.
groupsThey work like the GenCreate and GenUpdate view groups.
linkbackA list of fields will be excluded when rendering the object’s data. GenDetail will always show all the fields of the object. It will use (just like forms) the groups to show the information organized by them, and the rest of the fields will go consecutively at the end of the group. However, if a field appears in the exclude_fields list, it will not be displayed in the details view.

exclude_fields = ["contact", "price"]
linkeditIt shows the “Edit” button and defaults to True.

linkedit = True
linkdeleteIt shows the “Delete” button and defaults to True. This attribute is only available in editing forms (it is not enabled for creation forms since there is no record to delete).

linkdelete = True

GenDelete

from codenerix.views import GenDelete

class ContactDelete(GenDelete):
    model = Contact

It is the view in charge of deleting the records. The reason for inheriting from GenDelete is that the system does certain security checks for record deletion, including permissions and integrity, that Django itself does not. It also responds appropriately to the controllers that deal with the management of the forms.

So far, we have explained everything necessary to operate with the Generic views of CODENERIX.