Programacion Interactiva

Descubre una Nueva y Poderosa Herramienta.

FrameWork de Nueva Generacion

Acceso a tu Informacion desde cualquier Dispositivo con Navegador.

Enfoque en el Backend

Frontend de forma facil con Odoo y XML.

Creacion de Verticales

Creacion de nuevas Verticales Conquistando nuevos Mercados.

Tu marca aqui mismo

Llega a miles de personas.

Publicidad

viernes, 31 de enero de 2014

Corregir Error Time Zone en Odoo (OpenERP 8.0)

Corregir el Error de la Zona Horario en Odoo (OpenERP 8.0)


    Se que muchos habrán notado que al crear registros después de las 6:00 PM los campos de Fecha/Fecha y Hora suelen cambiar para el siguiente día, esto es debido a que el ORM de OPEN utiliza el tipo de fecha y hora llamado 'UTC' en base de Datos, para corregir este error tenemos que hacer lo siguiente:

Tenemos que corregir el Archivo fields.py

Este archivo se localiza en la ruta server/openerp/osv/fields.py

Dentro del Archivo buscar 'UTC' y reemplazarlo por 'SCT'


Nota: 

Esto se Repite con todas las coincidencias que encuentre en el editor en ese archivo fields.py

Adicional a esto es muy importante indicar nuestra zona horaria en la variable de este archivo:

utc = pytz.timezone('UTC')

Aqui debemos indicar la zona horaria de nuestra preferencia, por ejemplo:


utc = pytz.timezone('America/Mexico_City')

 Una vez hecho esto guardamos, reiniciamos el server de Odoo (OPENERP 8.0) é intentamos nuevamente crear los Registros y vamos a poder observar que ahora se insertan correctamente los campos de Fecha y Hora.

lunes, 27 de enero de 2014

Crear Demonio de Arranque Odoo (OPENERP 8.0)

Hacer Funcionar Odoo (OPENERP 8.0) como un Servicio del Sistema

    Para que openerp-server pueda funcionar como un servicio de cualquier S.O. en Linux tenemos que entrar en la ruta:

/etc/init.d/

    Dentro de esta ruta debemos crear nuestro demonio le pondremos como nombre openerp-server-70 como referencia que es la versión 7.0 de OPENERP, y así poder tener distintos demonios para versiones diferentes,  para crear el archivo usamos el comando:

sudo nano openerp-server

    Damos Ctrl+O y Enter para guardar el archivo ahora tendremos en la ruta /etc/init.d nuestro demonio openerp-server-70, como la siguiente imagen:


viernes, 24 de enero de 2014

Redes Sociales en nuestros Modelos en OpenERP 7.0 y Odoo (OpenERP 8.0)

Agregar Redes Sociales en OpenERP 7.0 y Odoo (OpenERP 8.0)



    Desde la Versión 7.0 de OpenERP podemos observar en el pie de cualquier formulario la parte de Redes Sociales que de alguna manera de da un Plus a cualquier modelo de datos, para que podamos tener esa aplicación al momento de crear nuestros módulos en OpenERP tendríamos que agregar en nuestras clases el código siguiente:

1.- En la declaracion de nuestra Clase OSV tendriamos que agregar la linea:

    _inherit = ['mail.thread', 'ir.needaction_mixin'] ### Redes Sociales
  

lunes, 20 de enero de 2014

ENTENTIENDO LOS WORLFLOWS EN ODoo (OPENERP)

WORKFLOWS (FLUJOS DE TRABAJO).


    Los flujos de trabajo pueden ser asociados a cualquier objeto en OpenERP, y son enteramente personalizables.

Se utilizan para estructurar, y gestionar los ciclos de vida de objetos, y documentos.
Definiendo transiciones, trigger (eventos), etc. etc. con herramientas gráficas.
Como de costumbre, los flujos de trabajo, sus actividades (acciones o nodos), y sus transiciones (condiciones), se declaran como un fichero XML.

HERENCIA DE VISTAS Odoo (OPENERP)

HERENCIA DE VISTAS.

Igual que podemos heredar objetos, también podemos heredar vistas de la siguiente manera:
<?xml version="1.0" encoding="UTF­8"?>
<openerp>
   <data>
<!­­--

id='res_partner_xxxxx_form_view_inh'
 
Este es el nuevo identificador que identifica a la vista que estamos  definiendo. Tener en cuenta que termina en 'form_view_inh', esto lo hacemos por norma, para identificar que esta vista, es una vista que
hereda De otra.
'name': Mismo nombre que el ID pero separado por '.'
'res.partner': Objeto al que pertenece la vista de la cuál estamos  heredando.
'inherid_id': Aquí le indicamos el ID de la vista que estamos heredando. La '<carpetapadre> es la primera carpeta que se encuentra  en ADDONS, en la cuál se encuentra el fichero xml, en el que está
definida la vista.
-->

<record model="ir.ui.view" id="res_partner_form_view_inh">
      <field name="name">res.partner.form.view.inh</field>
      <field name="model">res.partner</field>
      <field name="type">form</field>
      <field name="inherit_id" ref="carpetapadre.idVistaPadre" />
      <field name="arch" type="xml">
 
         <field name="campoareemplazar" position="after">
 
                  <field name="nuevocampo" />
         </field>
         <notebook position="inside">
               <page string="Literal para la nueva pestaña">
                  <group col="2" colspan="2">
                        <separator string="Literal del separador" colspan="2"/>
                        <field name="nuevocampo2"/>
                        <field name="nuevocampo3" nolabel="1"/>
                  </group>
               </page>
         </notebook>
   </field>
   </record>
   </data>
</openerp>

RELACIONES ENTRE OBJETOS.

MANEJO DE CAMPOS RELACIONALES EN Odoo (OPENERP)


one2many (de uno a muchos).

Una relación de uno a muchos sería por ejemplo la relación entre autores y libros. Un autor puede tener escritos varios libros, y varios libros pueden pertenecer a un autor. La relación sería de 1 a N.

Ejemplo de definición de la clase autor:

class mybookstore_author(osv.osv):
   _name ='mybookstore.author'
   _description ='Autores'
   _columns= {
      'name': fields.char('Name', size=64, required="True"),
      'active': fields.boolean('Active'),
      'book_ids': fields.one2many('mybookstore.book', 'author_id', 'Books'),
   }

mybookstore_author()

Atributos en Formularios de Odoo (OPENERP)

ATRIBUTOS DEL ELEMENTO DE FORMULARIO <FIELD>


attrs (condiciones de solo lectura, invisible, y requerido).

Cuando definimos un atributo 'attr' a un campo <field>, estamos definiendo una condición.

          Las condiciones que podemos definir es que el campo sea solo de lectura, requerido, o invisible.
Supongamos que tenemos definido en nuestro archivo de Phyton una clase con los siguientes campos:

'historial': fields.boolean('Historial', help="Marque casilla si historial"),
'historial_desc': fields.char('Description', size=64),

Y en la vista, esta es la definición de los campos:

<field name="historial"/>
<field name="historial_desc" attrs="{'invisible': [('historial, '=', False)]}"/>

El campo 'historial_desc' será invisible si el campo 'historial' (booleano) es igual a 'False'.

on_change (trigger que ejecuta una función cuando el valor del campo cambia).


    Cuando el valor del 'field' cambia, automáticamente ejecuta la función que definamos en el atributo 'onchange'. La funcion 'onchange' SIEMPRE DEVUELVE EL PARAMETRO 'value'.

Ejemplo:

<field name="historial"/>
<field name="historial_des" on_change="onchange_historial_des(historial_desc)"     attrs="{'invisible': [('historial', '=', False)]}"/>

Cuando el valor del campo 'onchange_historial_desc'. 'historial_desc' cambie, ejecutaremos la función :

def onchange_historial_desc(self, cr, uid, ids, historial_desc, context={}):
    res = {}
    for xxxx in self.browse(cr, uid, ids):
            res = {
                'historial_desc': (xxxx.historial_desc or '') + _('\n') +  (historial_desc or ''),
            }
        return {'value': res}

    En esta primera opción, no estoy haciendo caso al parámetro 'historial_des', ya que en este campo no viene un ID, sino un texto. Por lo tanto, hago referencia al parámetro de entrada 'ids'.

Opción 2 de la función:

def onchange_historial_des(self, cr, uid, ids, historial_id, context={}):
    res = {}
    if historial_id:
       xx_obj = self.pool.get('xxxx')
       xx = xxxx_obj.browse(cr, uid, historial_id)
       res = {
                'historial_des': (xxxx.historial_desc or '') + _('\n') +  (historial_des or ''),
          }
       return {'value': res

Como Funciona la Herencia en Odoo (OpenERP)


HERENCIA DE CLASES Y METODOS Odoo (OPENERP)

_inherit (Herencia de objetos).

    Al hacer referencia a este atributo, hacemos referencia a la HERENCIA. Un hijo hereda
todos los campos, y funciones de su padre.

Ejemplo: 

    Como todos sabemos, existe una clase que se llama “res.partner”. En el siguiente ejemplo vamos a crear una nueva clase que herede de “res.partner”. A esta nueva clase le añadiremos 2 Campos uno para Identificar que elementos de "res.partner" (Clientes/Proveedores) tienen facebook y cual seria el facebook de dichos registros:

 Esta sería la declaración de la nueva clase:

class res_partner(osv.osv):

<!--­­ Aqui indico el atributo 'name' del Objeto Padre ­­-->

_inherit ='res.partner'
     
<!--­­ Nuevo campo que voy a añadir al Objeto res.partner ­­-->
   
_columns= {
    'facebook': fields.boolean('Facebook'),
    'facebook_description': fields.boolean('URL Facebook'),
}
 
res_partner()

 Heredar funciones, y llamar a funciones padre con SUPER.

     A veces nos puede interesar heredar una función de una clase, para poder modificarla. Vamos a poner como ejemplo la función 'onchange_xxxxx' que está definida en la clase 'mi.clase'.

       Esta función se ejecuta cada vez que cambiemos el id de “mi.clase”, así que imaginemos que queremos cambiar el funcionamiento de dicha función. Teniendo en cuenta que en mi.clase existe la función onchange_xxxxx(self, cr, uid, ids, part), vamos a ver el siguiente ejemplo:

class mi_clase(osv.osv):

    <!--­­ HEREDAMOS DE LA CLASE ­­-->

    _inherit = 'mi.clase'

    <!--­­ DECLARAMOS OTRA VEZ LA FUNCIÓN QUE VAMOS A MODIFICAR --­­>
 
    def onchange_xxxxx(self, cr, uid, ids, part):
        value = {}
        miclase_obj = self.pool.get('mi.clase')

  <!­­-- LLAMAMOS A LA FUNCION PADRE ­­-->

  <!­­-- super(mi_clase,self): De esta manera llamamos a la función padre.   Hay que pasarle 2 parámetro: la clase padre, y 'self' ­­ -->

        res = super(mi_clase, self).onchange_xxxxx(cr, uid, ids, part)
        value = res['value']
        if part:
            miclase = miclase_obj.browse(cr, uid, part)

<!--­­  Modificamos 'value', si en value existe 'client_order_ref'  modifica su valor, si no existe, lo crea  dentro de value  -->
            value.update({
               'client_order_ref': miclase.name,
            })
  <!­­ La función 'onchange' siempre devuelve un value ­­>

return {'value': value}
 
sale_order()

lunes, 13 de enero de 2014

Reglas en Odoo (OpenERP) utilizando campos Many2Many y One2Many



Reglas con Campos Many2Many y One2Many


    Durante la creación de Reglas para Grupos en OpenERP en ocasiones tenemos que utilizar  campos many2many ó one2many para comparar que un valor se encuentre dentro de una lista de valores.

    Por ejemplo cuando trabajamos en un entorno Multicompañia en OpenERP en ocasiones tenemos errores durante el manejo de Modelos que tengan Acceso a campos que utilicen la campos con referencia a compañía, por ejemplo si queremos la comprobación de que un elemento se encuentra dentro de una lista ó que un campo compañia se encuentre dentro del campo company_ids que se encuentra en Usuarios y que contiene una lista de compañias a las cuales el usuario puede tener acceso, tendríamos que agregar en la creación de regla el dominio siguiente:

[('company_id','in',[x.id for x in user.company_ids])]

 - company_id: Es el campo que encuentra en el modelo OpenERP al cual quiero ligar con mi regla.

 - in: Es el la palabra reservada para comparar que un elemento se encuentra dentro de una lista.

 - [x.id for x in user.company_ids]: En esta linea  utilizamos un poco de código Python para crear una lista con los valores para la comparación de mi dominio, x.id es el valor obtenido de un ciclo for utilizando una variable x para la iterar dentro de el campo user.company_ids que contiene la relación many2many con el modelo de compañia. Al Final nos quedaría en ejecución algo como lo siguiente [('10','in',[1,5,15,10,25,35,2])], esto da como resultado True o False depensiendo si el valor 10 se encuentra dentro de los valores 1, 5, 15, 10, 25, 35, 2. A este proceso se le conoce en Python como Listas de Comprensión 


jueves, 9 de enero de 2014

Manejo de Campos many2many en Odoo (OPENERP)

Manejo de Campos many2many 



    En OPENERP es muy común que encontrásemos en el código de algunos módulos la utilización de campos relacionales may2many, los cuales contienen la siguiente sintaxis:

(0, 0, { fields }) Crear nuevos registros con la lista de campos.
(1, ID, { fields }) Modificar la lista de campos.
(2, ID) Borrar un id de la relación many2many.
(3, ID) Quitar (desvincular) un id de la relación manay2many.
(4, ID) Vincular un id
(5, ID) Desvincular todas las veces que aparece un id
(6,?, IDS) Establecer una lista de enlaces

    Por ejemplo para enlazar los impuestos de un producto al crear una linea en pedidos de venta o en lineas de factura nuestros valores quedarían de la siguiente manera:

pedido_padre_id = 65
product_obj = self.pool.get('product.product')
product_id = product_obj.search(cr, uid, [('name','=','Soda 2.5 Litros')])
product_browse = product_obj.browse(cr, uid, product_id, context=None)[0]

 linea_venta = {
                'product_id'           :  product_browse.id,
                'product_uom_qty' :  1,
                'product_uom'     : product_browse.uom_id.id,
                'product_uos_qty' : 1,
                'price_unit'          : product_browse.list_price,
                'name'                 : product_browse.name,
                'type'                   : 'make_to_stock',
                'default_code'      : product_browse.default_code,
                'tax_id'                : [(6, 0, [x.id for x in line.product_id.taxes_id])],
                'order_id'             :  pedido_padre_id,
            })

 order_line_id = self.pool.get('sale.order.line').create(cr, uid, linea_venta, context=None)

   Que pasa en este ejemplo estoy creando una linea para el pedido de venta con el ID 65 en la cual estoy pasando la información del producto 'Soda de 2.5 Litros' hacia mi linea, el punto mas importante en este ejemplo ó la que estamos estudiando es  'tax_id' : [(6, 0, [x.id for x in line.product_id.taxes_id])], que estamos haciendo en esta parte del código, estamos enlazando los impuestos del producto anterior en mi linea de pedido, ésto nos evita que nosotros realicemos la creación de cada impuesto al momento de mandar cada linea a un pedido de venta.
    

miércoles, 8 de enero de 2014

Métodos ORM Básicos para Programar Modulos en Odoo (OpenERP)

Métodos ORM básicos (Crear, Buscar, Leer, Actualizar y Borrar)

Método create

Sintaxis

create (cr, uid, values, context=None)

Crea un nuevo registro con los valores especificados. Parámetros específicos:

values: Diccionario con los valores de los campos para el nuevo registro.

Devuelve el id del registro creado. Puede generar los siguientes errores:

AccessError: Si el usuario no tiene permisos de escritura en el objeto solicitado, o si el usuario intenta
ignorar las reglas de acceso para crear el objeto solicitado.

ValidateError: Si el usuario intenta introducir un valor inválido para un campo que no está en la
selección.

UserError: Si se crease un bucle en una estructura de objetos jerárquica como resultado de la operación (como establecer un objeto como su propio padre).

Por ejemplo para crear un producto tendriamos que generar el diccionario con los valores necesarios, principalmente los que son requeridos por el Modelo:

product_obj = self.pool.get('product.product')

product_vals = {
                         'name': 'Producto X',
                         'type': 'product' ,
                         'list_price': 45.00,
                         'procure_method': 'make_to_stock',
                         }

product_create_id = product_obj.create(cr, uid, product_vals, context=None)

Parámetros comunes a la mayoría de métodos ORM en Odoo (OPENERP)



La mayoría de métodos ORM tiene una serie de parámetros comunes a todos ellos:

  •cr: Cursor de la base de datos
  •uid: Identificador del usuario actual
  •ids: Lista de enteros con los identificadores de los registros (o lista con un único entero cuando hay       sólo un id)
  •context: Diccionario con los argumentos de contexto, como idioma, zona horaria, ...

    Al definir nuestros modelos como herencia de la clase osv.osv permite que todos los métodos de ORM estén disponibles para la programación de los módulos. Estos métodos pueden ser invocados por los propios objetos, dentro de la clase Python, o desde fuera de la clase, obteniendo en primer lugar una instancia a través del concentrador (pooler) del sistema de ORM.

Contexto de los métodos ORM


    En OpenObject, el contexto tiene datos muy importantes, como el idioma en que se debe escribir un documento, si el campo de una función necesita actualizarse o no, ...

    Cuando se efectúa una llamada a un método ORM, es probable que el objeto ya tenga un contexto y el OpenObject lo proporcione como un parámetro en casi todos los métodos. Si el objeto tiene un contexto, es muy importante que siempre se pase el mismo a todos los métodos a los que se llame.

    Esta regla también es aplicable a los métodos ORM que escriba un programador. El programador debe esperar recibir un contexto como parámetro en todos los métodos que desee llamar, y siempre debe pasar el contexto a todos los métodos a los que llame.


lunes, 6 de enero de 2014

INSTALACION DE OPENERP 7.0 EN UBUNTU, UBUNTU SERVER, 12.X y 13.X


OpenERP Logo
Que tal buenas tardes a todos en este tutorial enseñare como instalar OpenERP en Ubuntu 12.04, aplica tambien para 12.10 y otras distribuciones de Linux como Debian, Linux Mint, entre otras.....

Si alguno no sabe que es OpenERP o un ERP aqui esta el concepto:

"OpenERP es un conjunto de soluciones integradas para gestión empresarial.
OpenERP automatiza y simplifica los procesos de negocio con la cadena de suministro, con la cadena logística, con la gestión de los clientes, con la lógica financiera, con los recursos humanos de la empresa... y  definitiva con todas y cada una de las áreas inherentes a cualquier modelo de negocio. Bajo licencia libre, multiplataforma y con posibilidad de uso bien mediante interfaz web o aplicación de escritorio, la información y la gestión empresarial siempre están accesibles desde cualquier lugar."

Realizar Respaldo y Restauración Base de Datos de OpenERP 7.0 desde Terminal o Linea de Comandos Utilizando PostgreSQL 9.1 y 9.2

Que tal muy buenas tardes en este tutorial explicaremos como poder realizar un backup o respaldo y restauracion de nuestra base de datos de openerp con postgresql. Antes que nada utilzaremos el comando pg_dump podemos informanos un poco mas en el siguiente enlace:

  http://www.postgresql.org/docs/9.1/static/app-pgdump.html

 Para realizar un respaldo o también conocido como backup de nuestras base de datos de OpenERP mediante postgrest mediante terminal ejecutaremos el siguiente comando en donde especificaremos la base de datos a restaurar en este caso se nombro TMS, el usuario despues de la letra -U en este caso mi usuario de postgres relacionado con openerp se nombro durante mi instalacion como openerp70, en la letra -h definimos el servidor de nuestra instalacion de openerp en este caso ejecutamos el comando localmente asi que nuestro servidor local por defecto seria localhost, despues insertamos el puerto que utiliza nuestro servicio despues de la leta -p en este caso por defecto utiliza openerp el puerto 5432 y por ultimo especificamos la ruta donde guardara el archivo de restauracion de nuestra base de datos en este caso la ruta de utilizacion fue /opt/openerp y de ahí el nombre con el que se guardara nuestro respaldo en este caso el nombre utilizado es dbbackup tambien podemos añadir que se comprima nuestra base de datos agregandole -Z y un numero de compresion de archivos que va del rango 1 a 9, el numero 9 seria la compresion maxima de un archivo, al fina de la ruta solo se le agrega .gz a tu backup y listo!!!!

 En este caso lo realizare sin la compresion, quedando asi el siguiente comando: pg_dump TMS -Fp -U openerp70 -h localhost -p 5432 > /opt/openerp/dbbackup

  Nota: El comando pg_dump se ejecuta fuera del superusuario de postgres...

Agregar nuevos campos en formularios OpenERP 7 sin necesidad de crear modulos

AGREGAR CAMPOS EN PEDIDO DE VENTA

     OpenERP tiene la facilidad y flexibilidad de poder agregarle nuevos campos a cualquier formulario de cualquier modulo directamente en el servicio sin necesidad de crear un modulo que realice esto, esto es muy eficiente y de mucha ayuda al momento de implementar OpenERP, ya que en ocasiones los campos que contienen los modulo no satisfagan nuestras necesidades, por ejemplo en pedido de venta necesitamos un nuevo campo denominado detalles de la venta este campo contendra hasta 200 caracteres para realizar esto realizaremos lo siguiente:

Entramos a OpenERP mediante nuestro navegador web y nos dirigirnos a la siguiente ruta:

Configuración --> Personalizacion --> Estructura de la Base de Datos --> Modelos



Campos Funcionales con OpenERP

En OpenERP un campo funcional es un campo cuyo valor no sera definido por el usuario sino el resultado de una funcion (estos campos no se guardan en base de datos ). En ocasiones, para aumentar la velocidad de consulta de OpenERP y facilitar las búsquedas, los campos funcionales también pueden ser guardados en la base de datos aunque siempre son calculados/actualizados por una o varias funciones y no por el usuario
.
La estructura de un campo funcional es la Siguiente:
fields.function(fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type="float, fnct_search=None, obj=None, method=False, store=False, multi=False,...)

Desarrollo de modulos para OpenERP 6.1, 7.0, 8.0

El desarrollo de modulos en OpenERP esta basado en el modelo MVC (Modelo Vista Controlador) y  ORM como su mapeo relacional de objetos, utilizando Python como lenguaje de programacion base y XML para poder generar las vistas de nuestro modulo, PostgreSQL como nuestro gestor de bases de datos, para programar modulos en OpenERP, no se necesita ser un experto en Python, simplemente con entender la base de Python, el manejo de las listas, tuplas y diccionarios y la definicion de funciones.
Para poder desarrollar modulos para OpenERP es necesario conocer un poco sobre el ORM ya que OpenERP tiene sus propias reglas para el desarrollo de sus modulos, una estructura necesaria para que nuestro modulo pueda ser instalado dentro de nuestro OpenERP, para el manejo de nuestras versiones de OpenERP utilizamos Launchpad (https://launchpad.net/) como sitio web y aplicacion web para poder mantener el versionamiento de nuestro modulo o modulos en desarrollo, y asi poder cooperar con la comunidad de software libre.
El siguiente video es desarrollado por el Ing. Israel Cruz Argil donde se trata de mostrar el desarrollo de un modulo OpenERP tocando algunos de los puntos anteriores:

Si necesitan mas informacion sobre etiquetas de XML para las estructuras de vistas para nuestro modulo visiten: http://doc.openerp.com/v6.1/developer/index.html#book-develop-link

Idioma Personalizado para OpenERP

Idioma Personalizado OpenERP
Como ya conocemos OpenERP es un sistema demasiado flexible, nos permite editar vistas, objetos directamente en el sistema, basándonos en esta "propiedad" de OpenERP podemos definir una Traducción Personalizada de nuestro Idioma, ya que en ocasiones la traducción por defecto en OpenERP no es muy clara o algunas palabras están traducidas a un nivel estándar  para solucionar este problema podemos generar una Traducción propia para que posteriormente pudiéramos reutilizarla o en su caso compartirla con la comunidad de OpenERP.

Instalación de Jasper Reports en OpenERP 7.0

El manejo de Reportes con Jasper Reports en OpenERP se dejo a un lado desde la versión 7.0 pero es una excelente opción al momento de crear reportes para cualquier modelo de OpenERP, para ello de ah modificado el Modulo Jasper Reports para hacerlo compatible con la versión 7.0 del ERP. Si no conocen sobre Jasper Reports les recomiendo el siguiente enlace:

Restricciones en OpenERP mediante PostgreSQL

En OpenERP existen 2 Tipos de principales para validar la información que esta introduciendo el usuario contra la contenida en el sistema, ya sea contra la hora del sistema o algún formato necesario para la información, etc., estos tipos de validación serian:
 - Mediante funciones Python: Este tipo de restricción se realiza mediante funciones python.
 - Mediante restricciones de la Base de Datos(SQL Constraint): Este tipo de restricción se define en la clase a la cual se aplicara o la tabla a la cual se estará validando que los datos cumplan con los requisitos que definimos, por ejemplo si queremos que el campo nombre de un producto sea único tendríamos que tener esta restricción en mi clase.
Restricciones con Funciones Python