{"id":644,"date":"2017-07-05T19:11:00","date_gmt":"2017-07-05T19:11:00","guid":{"rendered":"https:\/\/geoadmin.com.br\/?p=644"},"modified":"2021-06-09T10:24:06","modified_gmt":"2021-06-09T13:24:06","slug":"django-topology","status":"publish","type":"post","link":"https:\/\/geoadmin.com.br\/?p=644","title":{"rendered":"Django Topology"},"content":{"rendered":"<p>Ol\u00e1 pessoal!<\/p>\n<p>Aqui na SIGMA sempre estamos desenvolvendo ferramentas \u00fateis para n\u00f3s e que talvez tamb\u00e9m sejam \u00fateis para outras pessoas.<\/p>\n<p>Nossa ideia principal, \u00e9 contribuir um pouco com esse enorme ecossistema Python\/Django existente. Como j\u00e1 disseram, estamos sobre os ombros de gigantes.<\/p>\n<p>Bem, desenvolvemos o <a href=\"https:\/\/gitlab.sigmageosistemas.com.br\/dev\/django-topology\">Django Topology<\/a> com o objetivo de simplificar a valida\u00e7\u00e3o de dados geom\u00e9tricos\/geogr\u00e1ficos que encontramos em nosso dia a dia.<\/p>\n<p>\u00c9 muito comum, por exemplo, ter de validar a entrada de um pol\u00edgono e precisamos garantir que ele esteja dentro de outro pol\u00edgono. Ou garantir que este pol\u00edgono espec\u00edfico n\u00e3o esteja sobrepondo outro pol\u00edgono de uma mesma classe.<\/p>\n<p>Para isso desenvolvemos o <a href=\"https:\/\/gitlab.sigmageosistemas.com.br\/dev\/django-topology\">Django Topology<\/a>. Atrav\u00e9s dele voc\u00ea consegue configurar suas valida\u00e7\u00f5es dentro do banco de dados e execut\u00e1-las de forma simples.<\/p>\n<p>O fluxo \u00e9 simples e o pacote j\u00e1 conta com tr\u00eas valida\u00e7\u00f5es:<\/p>\n<ul>\n<li>must be contained &#8211; garante que o modelo A deve estar contido no modelo B;<\/li>\n<li>must not overlap &#8211; garante que o modelo A n\u00e3o pode sobrepor nenhum outro registro em A;<\/li>\n<li>must not overlap with &#8211; garante que o modelo A n\u00e3o pode sobrepor o modelo B;<\/li>\n<\/ul>\n<p>O pacote \u00e9 facilmente extens\u00edvel e voc\u00ea desenvolver suas pr\u00f3prias valida\u00e7\u00f5es topol\u00f3gicas.<\/p>\n<p>Um exemplo simples:<\/p>\n<pre><code class=\"python\">        rule = Rule(\n            name='regra de valida\u00e7\u00e3o 1',\n            description='A deve estar contido em B',\n            message='deve estar contido',\n            method='topology.rules.must_be_contained'\n        )\n        rule.save()\n        topology_rule = TopologyRule(\n            content_type_a=ContentType.objects.get(app_label='seuapp', model='item'),\n            content_type_b=ContentType.objects.get(app_label='seuapp', model='container'),\n            geom_field_b='geom',\n            rule=rule\n        )\n        topology_rule.save()\n<\/code><\/pre>\n<p>At\u00e9 aqui, definimos nossa regra topol\u00f3gica, de que A (qualquer inst\u00e2ncia do modelo Item) <strong>deve<\/strong> estar contida em B (Container).<\/p>\n<p>Veja como realizar a valida\u00e7\u00e3o:<\/p>\n<pre><code class=\"python\">        item_a = Item(geom=unit_polygon(Point(x=0.0, y=0.0, srid=4326)))\n        item_a.save()\n        container = Container(geom=unit_polygon(Point(x=0.0, y=0.0, srid=4326), size=3))\n        container.save()\n\n        errors = topology_rule.validate(item_a)\n        len(errors)\n&gt;&gt;&gt; 3\n<\/code><\/pre>\n<p>No exemplo acima, calculamos os erros diretamente pela regra topol\u00f3gica (TopologyRule) e n\u00e3o foi encontrado nenhum erro.<\/p>\n<p>Os erros gerados pelo TopologyRule <strong>n\u00e3o s\u00e3o persistidos<\/strong> no banco de dados, ficando a cargo do desenvolvedor a determinar o melhor momento para tal. As vezes nem ser\u00e1 necess\u00e1rio, como por exemplo, em uma valida\u00e7\u00e3o de formul\u00e1rio Django.<\/p>\n<p>Tamb\u00e9m desenvolvemos um an\u00e1logo ao <strong>TopologyChecker<\/strong> do QGIS e ele tem o mesmo nome. Sua fun\u00e7\u00e3o \u00e9 executar <strong>todas<\/strong> as valida\u00e7\u00f5es associadas a um determinado modelo, de uma vez, e persisti-las (ou n\u00e3o).<\/p>\n<p>Veja como us\u00e1-lo:<\/p>\n<pre><code class=\"python\">        # definindo as regras\n        rule1 = Rule(\n            name='A n\u00e3o deve sobrepor A',\n            description='A n\u00e3o deve sobrepor A',\n            message='sobrep\u00f5e',\n            method='topology.rules.must_not_overlap'\n        )\n        rule1.save()\n        rule2 = Rule(\n            name='A n\u00e3o deve sobrepor B',\n            description='A n\u00e3o deve sobrepor B',\n            message='sobrep\u00f5e',\n            method='topology.rules.must_not_overlap_with'\n        )\n        rule2.save()\n        topology_rule1 = TopologyRule(\n            content_type_a=ContentType.objects.get(app_label='seuapp', model='item'),\n            rule=rule1\n        )\n        topology_rule1.save()\n        topology_rule2 = TopologyRule(\n            content_type_a=ContentType.objects.get(app_label='seuapp', model='item'),\n            content_type_b=ContentType.objects.get(app_label='seuapp', model='container'),\n            geom_field_b='geom',\n            rule=rule2\n        )\n        topology_rule2.save()\n\n        item1 = Item(geom=unit_polygon(Point(x=0.0, y=0.0, srid=4326)))\n        item1.save()\n        item2 = Item(geom=unit_polygon(Point(x=0.0, y=0.0, srid=4326)))\n        item2.save()\n        container = Container(geom=unit_polygon(Point(x=0.0, y=0.0, srid=4326), size=2))\n        container.save()\n\n        # at\u00e9 aqui, criamos nossas regras e os registros de item e container\n\n        topo_checker = TopologyChecker()\n\n        errors = topo_checker.validate_all(Item)\n<\/code><\/pre>\n<p>O <strong>TopologyChecker<\/strong> retorna um dicion\u00e1rio, usando como chave o nome da valida\u00e7\u00e3o executada e uma lista associada, com N erros detectados. No caso acima, o topologychecker encontrou 4 erros:<\/p>\n<ul>\n<li>item 1 sobrep\u00f5e item 2;<\/li>\n<li>item 2 sobrep\u00f5e item 1;<\/li>\n<li>item 1 sobrep\u00f5e Container 1;<\/li>\n<li>item 2 sobrep\u00f5e COntainer 1;<\/li>\n<\/ul>\n<p>Estamos usando o <a href=\"https:\/\/gitlab.sigmageosistemas.com.br\/dev\/django-topology\">Django Topology<\/a> em produ\u00e7\u00e3o no <a href=\"https:\/\/geoadmin.com.br\">Geoadmin<\/a> um produto que trabalha intensivamente com dados geogr\u00e1ficos.<\/p>\n<p>Voc\u00ea pode extender o mesmo com suas pr\u00f3prias valida\u00e7\u00f5es. Basta criar um m\u00e9todo com a seguinte assinatura:<\/p>\n<pre><code class=\"python\">def minha_validacao(rule, feature, **kwargs):\n    # sua validacao aqui\n    # deve retornar uma lista de TopologyError (sem salvar no banco)\n    if feature.geom.intersects(outra_geometria):\n        return [TopologyError()]\n\n    return []\n<\/code><\/pre>\n<p>Com este m\u00e9todo pronto, voc\u00ea s\u00f3 precisa criar uma Rule, apontando o atributo method para o caminmho qualificado da sua fun\u00e7\u00e3o:<\/p>\n<pre><code class=\"python\">rule = Rule(\n    name='name'\n    method='foo.bar.minha_validacao\n)\n<\/code><\/pre>\n<p>Quer ajudar? Estamos a\u00ed, confere o reposit\u00f3rio e bora l\u00e1.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ol\u00e1 pessoal! Aqui na SIGMA sempre estamos desenvolvendo ferramentas \u00fateis para n\u00f3s e que talvez tamb\u00e9m sejam \u00fateis para outras pessoas. Nossa ideia principal, \u00e9 contribuir um pouco com esse enorme ecossistema Python\/Django existente. Como j\u00e1 disseram, estamos sobre os ombros de gigantes. Bem, desenvolvemos o Django Topology com o objetivo de simplificar a valida\u00e7\u00e3o &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/geoadmin.com.br\/?p=644\" class=\"more-link\">Leia mais<span class=\"screen-reader-text\"> &#8220;Django Topology&#8221;<\/span><\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4,1],"tags":[67,72,53,73,70,27,31,45],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/posts\/644"}],"collection":[{"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=644"}],"version-history":[{"count":1,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/posts\/644\/revisions"}],"predecessor-version":[{"id":679,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=\/wp\/v2\/posts\/644\/revisions\/679"}],"wp:attachment":[{"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/geoadmin.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}