{% for m in proto.messages %}{% if not m.options.skip_django -%}
{% if file_exists(xproto_base_name(m.name)|lower+'_header.py') -%}from {{xproto_base_name(m.name)|lower }}_header import *{%- else -%}from header import *{% endif %}
{% if file_exists(xproto_base_name(m.name)|lower+'_top.py') -%}{{ include_file(xproto_base_name(m.name)|lower+'_top.py') }} {% endif %}
{%- for l in m.links %}

{% if l.peer.name != m.name %}
from {{ l.peer.name | lower }} import {{ l.peer.name }} 
{% endif %}

{%- endfor %}
{% if m.name!='XOSBase' and 'Mixin' not in m.name %}
import security
{% if m.name!='Privilege' %}
from privilege import Privilege
{% endif %}
{% endif %}
{% for b in m.bases %}
{% if b.name!='XOSBase' and 'Mixin' not in b.name %}
from {{b.name | lower}} import {{ b.name }}
{% endif %}
{% endfor %}

{% for policy,error in xproto_validations(m.options) %}
{{ xproto_fol_to_python_validator(policy, proto.policies[policy], m, error) }}
{% endfor %}

class {{ m.name }}{{ xproto_base_def(m.name, m.bases) }}:
  plural_name = "{{ xproto_pluralize(m) }}"

{#  {% if m.options.no_sync or m.options.no_policy %}#}
{#  {% if m.options.no_sync -%}#}
{#  # Removing synchronizer feedback state from model#}
{#  backend_status = None#}
{#  backend_code = None#}
{#  {%- endif %}#}
{#  {% if m.options.no_policy -%}#}
{#  # Removing model policy feedback state from model#}
{#  policy_code = None#}
{#  policy_status = None#}
{#  {%- endif %}#}
{#  {% endif %}#}

  # Primitive Fields (Not Relations)
  {% for f in m.fields %}
  {%- if not f.link -%}
  {{ f.name }} = {{ xproto_django_type(f.type, f.options) }}( {{ xproto_django_options_str(f) }} )
  {% endif %}
  {%- endfor %}

  # Relations
  {% for l in m.links %}{% set peer_name=l.peer.name %}
  {{ l.src_port }} = {{ xproto_django_link_type(l) }}( {%- if peer_name==m.name -%}'self'{%- else -%}{{ peer_name }} {%- endif -%}, {{ xproto_django_link_options_str(l, l.dst_port ) }} )
  {%- endfor %}

  # Meta
  {%- set uniques = xproto_field_graph_components(m.fields) %}
  {%- if uniques %}
  class Meta:
      unique_together = {{ xproto_tuplify(uniques) }}
  {%- endif %}
  {% if file_exists(m.name|lower + '_model.py') -%}{{ include_file(m.name|lower + '_model.py') | indent(width=2)}}{%- endif %}
  pass

  {% if m.name!='XOSBase' and 'Mixin' not in m.name %}
  # Generated methods
  def save(self, *args, **kwds):
      if not self.leaf_model_name:
          self.leaf_model_name = "{{ m.name }}"

      try:
          self.__xos_save_base(*args, **kwds)
      except AttributeError:
          pass

      {% for policy,error in xproto_validations(m.options) %}
      policy_{{policy}}_validator(self, None)
      {% endfor %}
      super({{ m.name }}, self).save(*args, **kwds)

  def can_access(self, ctx):
      {% if m.policy %}
      verdict = security.{{m.policy}}_security_check(self, ctx)
      return verdict,"{{ m.policy }}"
      {% else %}
      verdict = XOS_GLOBAL_DEFAULT_SECURITY_POLICY
      return verdict,"xos_default_policy"
      {% endif %}
      
  {% endif %}
    
{% if file_exists(xproto_base_name(m.name)|lower+'_bottom.py') -%}{{ include_file(xproto_base_name(m.name)|lower+'_bottom.py') }}{% endif %}
{% endif %}{% endfor %}
