【Admin后台管理】Geodjango后台显示地图并加载空间字段

news2024/11/18 7:44:59

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。


文章目录

  • 前言
  • 一、django+admin
  • 二、geodjango+admin
  • 三、报错处理


前言

在前面的博客中,我们已经介绍了Geodjango的环境搭建和数据库操作,django本身提供了amdin后台,其实geodjango也有后台页面,现在我们来试着使用admin显示地图并加载空间字段。


一、django+admin

首先我们应该对django使用admin后台有一定基础,可以简单实现后台增删改查数据。

models.py文件如下

from django.contrib.gis.db import models
from django.utils import timezone

class SarPic(models.Model):
	...
    ImageGeoJSON = models.PolygonField('成像地理信息', null=True, help_text='Metadata:ImageGeoJSON')
    ...
    class Meta:
        verbose_name = '数据'
        verbose_name_plural = verbose_name

admin.py文件如下

from django.contrib import admin
from sarimage.models import SarPic

class SarPicAdmin(admin.ModelAdmin):
    list_display = ['ProductID',  'create_time', 'alter_time']
    list_per_page = 50
    list_filter = ['ImagingTime', 'SatellitePlatform', 'missionDataTakeId', 'SensorMode']
    # search_fields = ['ProductID', 'ImagingTime', 'SatelliteName', 'missionDataTakeId']
    fieldsets = (
        ('影像图像', {
            'fields': ('ImageGeoJSON',)
        })
    )

admin.site.register(SarPic, SarPicAdmin)

二、geodjango+admin

这里的变化为admin.ModelAdmin改为GeoModelAdmin(基于OpenLayers),除此之外还可以改成OSMGeoAdmin(基于OpenStreetMap)或LeafletGeoAdmin(基于Leaflet框架的第三方库django-leaflet)。

admin.py文件如下

from django.contrib import admin
from django.contrib.gis.admin import GeoModelAdmin
from sarimage.models import SarPic

class SarPicAdmin(GeoModelAdmin):
    list_display = ['ProductID',  'create_time', 'alter_time']
    list_per_page = 50
    list_filter = ['ImagingTime', 'SatellitePlatform', 'missionDataTakeId', 'SensorMode']
    # search_fields = ['ProductID', 'ImagingTime', 'SatelliteName', 'missionDataTakeId']
    fieldsets = (
        ('影像图像', {
            'fields': ('ImageGeoJSON',)
        })
    )
    default_lon  # 默认的中心经度。
	default_lat  # 默认的中心纬度。
	default_zoom  # 要使用的默认缩放级别。默认值为4。
	extra_js  # 要包含的任何额外javascript的URL序列。
	map_template  # 重写用于生成javascript Slippy映射的模板。默认是 'gis/admin/openlayers.html' .
	map_width  # 地图的宽度,以像素为单位。默认值为600。
	map_height  # 地图的高度,以像素为单位。默认为400。
	openlayers_url  # 链接到Openlayers JavaScript的URL。默认为 'https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js' .
    modifiable = False  # 禁用管理中现有几何图形字段的编辑

admin.site.register(SarPic, SarPicAdmin)

三、报错处理

按照第二部分设置后,会报错 django.template.exceptions.TemplateDoesNotExist: gis/admin/openlayers.html。
我不知道其他人遇到怎么处理的,网络上也没找相关方案。主要原因是django的版本不同,django库的文件存在差异,部分版本缺少geodjango的template文件夹,这个需要我们自己补全。
templates必须放入我们项目的app中,我的项目app是sarimage,models.py是空间数据的类。
在这里插入图片描述
在这里插入图片描述

from django.contrib.gis.admin import GeoModelAdmin

我使用的是geodjango默认的GeoModelAdmin,所以我需要的是openlayers.html和openlayers.js文件。

openlayers.html文件内容如下

{% block extrastyle %}
{% load i18n static %}{% get_current_language_bidi as LANGUAGE_BIDI %}
<style type="text/css">
  #{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; }
  #{{ id }}_map .aligned label { float:inherit; }
  #{{ id }}_admin_map { position: relative; vertical-align: top; z-index: 0; float: {{ LANGUAGE_BIDI|yesno:"right,left" }}; }
  {% if not display_wkt %}#{{ id }} { display: none; }{% endif %}
  .olControlEditingToolbar .olControlModifyFeatureItemActive {
     background-image: url("{% static "admin/img/gis/move_vertex_on.svg" %}");
     background-repeat: no-repeat;
  }
  .olControlEditingToolbar .olControlModifyFeatureItemInactive {
     background-image: url("{% static "admin/img/gis/move_vertex_off.svg" %}");
     background-repeat: no-repeat;
  }
</style>
{% endblock %}
<span id="{{ id }}_admin_map">
<script>
//<![CDATA[
{% block openlayers %}{% include "gis/admin/openlayers.js" %}{% endblock %}
//]]>
</script>
<div id="{{ id }}_map" dir="{{ LANGUAGE_BIDI|yesno:'rtl,ltr,auto' }}"></div>
{% if editable %}
<a href="javascript:{{ module }}.clearFeatures()">{% translate "Delete all Features" %}</a>
{% endif %}
{% if display_wkt %}<p>{% translate "WKT debugging window:" %} </p>{% endif %}
<textarea id="{{ id }}" class="vWKTField required" cols="150" rows="10" name="{{ name }}">{{ wkt }}</textarea>
<script>{% block init_function %}{{ module }}.init();{% endblock %}</script>
</span>

openlayers.js文件内容如下

{% load l10n %}
OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.SphericalMercator.projectForward);
{% block vars %}var {{ module }} = {};
{{ module }}.map = null; {{ module }}.controls = null; {{ module }}.panel = null; {{ module }}.re = new RegExp("^SRID=\\d+;(.+)", "i"); {{ module }}.layers = {};
{{ module }}.modifiable = {{ modifiable|yesno:"true,false" }};
{{ module }}.wkt_f = new OpenLayers.Format.WKT();
{{ module }}.is_collection = {{ is_collection|yesno:"true,false" }};
{{ module }}.collection_type = '{{ collection_type }}';
{{ module }}.is_generic = {{ is_generic|yesno:"true,false" }};
{{ module }}.is_linestring = {{ is_linestring|yesno:"true,false" }};
{{ module }}.is_polygon = {{ is_polygon|yesno:"true,false" }};
{{ module }}.is_point = {{ is_point|yesno:"true,false" }};
{% endblock %}
{{ module }}.get_ewkt = function(feat){
    return 'SRID={{ srid|unlocalize }};' + {{ module }}.wkt_f.write(feat);
};
{{ module }}.read_wkt = function(wkt){
    // OpenLayers cannot handle EWKT -- we make sure to strip it out.
    // EWKT is only exposed to OL if there's a validation error in the admin.
    var match = {{ module }}.re.exec(wkt);
    if (match){wkt = match[1];}
    return {{ module }}.wkt_f.read(wkt);
};
{{ module }}.write_wkt = function(feat){
    if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}
    else { {{ module }}.num_geom = 1;}
    document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);
};
{{ module }}.add_wkt = function(event){
    // This function will sync the contents of the `vector` layer with the
    // WKT in the text field.
    if ({{ module }}.is_collection){
        var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
        for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){
            feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
        }
        {{ module }}.write_wkt(feat);
    } else {
        // Make sure to remove any previously added features.
        if ({{ module }}.layers.vector.features.length > 1){
            old_feats = [{{ module }}.layers.vector.features[0]];
            {{ module }}.layers.vector.removeFeatures(old_feats);
            {{ module }}.layers.vector.destroyFeatures(old_feats);
        }
        {{ module }}.write_wkt(event.feature);
    }
};
{{ module }}.modify_wkt = function(event){
    if ({{ module }}.is_collection){
        if ({{ module }}.is_point){
            {{ module }}.add_wkt(event);
            return;
        } else {
            // When modifying the selected components are added to the
            // vector layer so we only increment to the `num_geom` value.
            var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
            for (var i = 0; i < {{ module }}.num_geom; i++){
                feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
            }
            {{ module }}.write_wkt(feat);
        }
    } else {
        {{ module }}.write_wkt(event.feature);
    }
};
// Function to clear vector features and purge wkt from div
{{ module }}.deleteFeatures = function(){
    {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);
    {{ module }}.layers.vector.destroyFeatures();
};
{{ module }}.clearFeatures = function (){
    {{ module }}.deleteFeatures();
    document.getElementById('{{ id }}').value = '';
    {% localize off %}
    {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
    {% endlocalize %}
};
// Add Select control
{{ module }}.addSelectControl = function(){
    var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});
    {{ module }}.map.addControl(select);
    select.activate();
};
{{ module }}.enableDrawing = function(){
    {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();
};
{{ module }}.enableEditing = function(){
    {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();
};
// Create an array of controls based on geometry type
{{ module }}.getControls = function(lyr){
    {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});
    {{ module }}.controls = [new OpenLayers.Control.Navigation()];
    if (!{{ module }}.modifiable && lyr.features.length) return;
    if ({{ module }}.is_linestring || {{ module }}.is_generic){
        {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'}));
    }
    if ({{ module }}.is_polygon || {{ module }}.is_generic){
        {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'}));
    }
    if ({{ module }}.is_point || {{ module }}.is_generic){
        {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'}));
    }
    if ({{ module }}.modifiable){
        {{ module }}.controls.push(new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'}));
    }
};
{{ module }}.init = function(){
    {% block map_options %}// The options hash, w/ zoom, resolution, and projection settings.
    var options = {
{% autoescape off %}{% for item in map_options.items %}      '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %}
{% endfor %}{% endautoescape %}    };{% endblock %}
    // The admin map for this geometry field.
    {% block map_creation %}
    {{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
    // Base Layer
    {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS("{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'{{ wms_options|safe }}});{% endblock %}
    {{ module }}.map.addLayer({{ module }}.layers.base);
    {% endblock %}
    {% block extra_layers %}{% endblock %}
    {% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
    {{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}");
    {{ module }}.map.addLayer({{ module }}.layers.vector);
    // Read WKT from the text field.
    var wkt = document.getElementById('{{ id }}').value;
    if (wkt){
        // After reading into geometry, immediately write back to
        // WKT <textarea> as EWKT (so that SRID is included).
        var admin_geom = {{ module }}.read_wkt(wkt);
        {{ module }}.write_wkt(admin_geom);
        if ({{ module }}.is_collection){
            // If geometry collection, add each component individually so they may be
            // edited individually.
            for (var i = 0; i < {{ module }}.num_geom; i++){
                {{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);
            }
        } else {
            {{ module }}.layers.vector.addFeatures([admin_geom]);
        }
        // Zooming to the bounds.
        {{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());
        if ({{ module }}.is_point){
            {{ module }}.map.zoomTo({{ point_zoom }});
        }
    } else {
        {% localize off %}
        {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
        {% endlocalize %}
    }
    // This allows editing of the geographic fields -- the modified WKT is
    // written back to the content field (as EWKT, so that the ORM will know
    // to transform back to original SRID).
    {{ module }}.layers.vector.events.on({"featuremodified" : {{ module }}.modify_wkt});
    {{ module }}.layers.vector.events.on({"featureadded" : {{ module }}.add_wkt});
    {% block controls %}
    // Map controls:
    // Add geometry specific panel of toolbar controls
    {{ module }}.getControls({{ module }}.layers.vector);
    {{ module }}.panel.addControls({{ module }}.controls);
    {{ module }}.map.addControl({{ module }}.panel);
    {{ module }}.addSelectControl();
    // Then add optional visual controls
    {% if mouse_position %}{{ module }}.map.addControl(new OpenLayers.Control.MousePosition());{% endif %}
    {% if scale_text %}{{ module }}.map.addControl(new OpenLayers.Control.Scale());{% endif %}
    {% if layerswitcher %}{{ module }}.map.addControl(new OpenLayers.Control.LayerSwitcher());{% endif %}
    // Then add optional behavior controls
    {% if not scrollable %}{{ module }}.map.getControlsByClass('OpenLayers.Control.Navigation')[0].disableZoomWheel();{% endif %}
    {% endblock %}
    if (wkt){
        if ({{ module }}.modifiable){
            {{ module }}.enableEditing();
        }
    } else {
        {{ module }}.enableDrawing();
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网易云音乐开发--前后端交互

前后端交互 首先启动服务器 1. 根目录下执行&#xff1a; npm start 2. 服务器地址&#xff1a; http://localhost:3000 3. 示例: http://localhost:3000/banner 测试接口能不能用 发起请求 看接口说明&#xff0c;在wx的load函数中发起请求 请求成功 封装请求功能函数 …

Django框架之ORM和模型属性

Django对很多数据库都有支持&#xff0c;为这些数据库提供了统一的调用API。可以根据不同的业务需求&#xff0c;选择配置不同的数据库。本篇文章主要介绍ORM和模型属性。 ORM ORM全称Object Relational Mapping&#xff0c;即对象关系映射&#xff0c;是在pymysq之上又进行了…

JAVAWeb11-服务器渲染技术 -JSP-01-JSP基础

1. 现状 1、JSP 使用情况 2、Thymeleaf 使用情况, 通常和 SpringBoot 结合(也会讲) 3、Vue 使用情况 2. 学 JSP 前&#xff0c;老师要说的几句话 目前主流的技术是 前后端分离 (比如: Spring Boot Vue/React), 我们会讲的.[看一下]JSP 技术使用在逐渐减少&#xff…

06 - 4 微内核架构

什么是微内核架构 定义 微内核 核心功能资源封装 插件 可插拔 系统核心 资源封装 硬件接口系统资源访问接口环境/上下文&#xff08;context&#xff09;访问接口系统事件接口 定义插件规范 使用场景规则条件 核心功能 支持系统运作的最小功能集 职责分离 通用流程由核心…

音视频八股文(10)-- mp4结构

介绍 mp4⽂件格式⼜被称为MPEG-4 Part 14&#xff0c;出⾃MPEG-4标准第14部分 。它是⼀种多媒体格式容器&#xff0c;⼴泛⽤于包装视频和⾳频数据流、海报、字幕和元数据等。&#xff08;顺便⼀提&#xff0c;⽬前流⾏的视频编码格式AVC/H264 定义在MPEG-4 Part 10&#xff09…

CTF权威指南 笔记 -第三章汇编基础-3.2-x86/x64汇编基础

这节介绍PC最常见的架构 x86和扩展 x64框架 CPU操作模式 对x86处理器而言 有三个最主要的保护模式 保护模式 实地址模式 系统管理模式还有一个保护模式的子模式 虚拟8086模式 保护模式 保护模式是处理原生状态 这个时候所有指令和特性都是可以使用的 分配给程序的独立内…

好用的原型设计软件有哪些?一次给你推荐12个

原型设计是项目需求可视化的过程&#xff0c;从事产品设计工作必须与产品原型的创建分不开&#xff0c;因此原型设计软件的选择不容忽视&#xff0c;一个好的原型设计软件&#xff0c;不仅能有效输出页面设计&#xff0c;规范产品原型&#xff0c;而且能有效降低开发和设计人员…

debootstrap 构建 RISC-V 64 Ubuntu 根文件系统

debootstrap 构建 Ubuntu RISC-V Linux 根文件系统 flyfish 主机信息 命令 lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal制作的根文件系统为 RISC-V 64 Ubuntu 22.04 LTS 1 主机…

Spring框架入门

Spring框架入门 简介开发环境入门案列Spring bean的定义常用属性 Spring IOC (控制反转)简介控制反转&#xff08;IoC&#xff09;案例 依赖注入&#xff08;DI&#xff09;IoC 容器的两种实现ApplicationContextBeanFactory Spring Bean属性注入构造函数注入setter 注入 Sprin…

洛谷 P2782 友好城市 线性DP 最长上升子序列 二分查找 lower_bound

&#x1f351; 算法题解专栏 &#x1f351; 洛谷&#xff1a;友好城市 题目描述 有一条横贯东西的大河&#xff0c;河有笔直的南北两岸&#xff0c;岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸&#xff0c;而且不同城市的友好城市不相同。每对…

关于HTTP服务小实验。

请给openlab搭建web网站 ​网站需求&#xff1a; ​1.基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! ​2.给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[www.openlab.com/student](ht…

充电桩测试设备TK4800充电桩现校仪检定装置

TK4800是一套专用于检定电动汽车非车载充电机现场校验仪和电动汽车交流充电桩现场校验仪的装置&#xff0c;充电桩测试设备装置针对新能源汽车充电动态特性进行设计&#xff0c;支持稳态电能计量&#xff08;针对恒定负载&#xff09;和动态电能计量&#xff08;针对波动性负载…

.NET中mysql 找不到请求的 .Net Framework Data Provider。可能没有安装。

如果你遇到 “找不到请求的 .Net Framework Data Provider。可能没有安装”这个问题&#xff0c;其他方式都试过了还不行&#xff0c;就试试下面这个方法吧&#xff0c;每次遇到同样的报错可能是不同的原因引起的&#xff0c;要具体排查尝试&#xff0c;反正我都遇到了个遍&…

Gitlab自动触发jenkins完成自动化构建

jenkins 首先安装gitlab插件&#xff0c;我已经安装过了&#xff0c;首次请在可选插件中进行搜索。 进入项目配置--构建触发器&#xff1a; Build when a change is pushed to GitLab. GitLab webhook URL: 请复制此处的URL&#xff0c;后续有用。 然后点击高级 “Allowed br…

拨云见日:深入理解 HTML 解析器与有限状态机

文章目录 参考描述状态机状态机有限状态机与无限状态机有限状态机与自动售货机无限状态机与计算器 HTML 解析器HTML 解析器HTML 与有限状态机 HTML 解析器的常见状态初始状态DOCTYPE 状态注释状态标签状态开始标签状态属性状态属性名状态属性值状态 结束标签状态自闭和标签状态…

大象起舞的秘密:深度剖析酒店“航母”时代新战略

4月19日-21日&#xff0c;因疫情阔别近两年的中国酒店投资及酒店产业系列展&#xff08;简称HFE&#xff09;在上海世博展览馆盛大举办&#xff0c;作为疫后首个举办的行业领先的酒店业展览会&#xff0c;本届HFE备受关注。 “品牌航母”锦江酒店&#xff08;中国区&#xff09…

springboot 整合 sharding-jdbc 主从 读写分离

目录 0 课程视频 1 mysql 主从搭建 1.1 docker mysql 主从搭建 1.2 非docker mysql 主从搭建 2 springboot sharding-jdbc 主从 读写分离 2.1 pom 加依赖 2.1 yml 配置文件 2.2 druid数据源冲突解决 -> 视频15:20 秒处 2.3 注入数据源对象 3 测试 -> 直接使用 …

Java使用Milo实现OPC UA客户端,封装spring boot starter

文章目录 一、milo库二、OPC UA服务端三、工具使用3.1 依赖3.2 配置3.3 连接池3.4 写3.4.1 通用类型3.4.2 已提供方法的类型3.4.3 其他类型 3.5 读3.6 遍历节点 一、milo库 由eclipse开源&#xff0c;地址&#xff1a;https://github.com/eclipse/milo&#xff0c;可以基于此开…

ChatGPT如何提问?30句ChatGPT提问公式,快收藏

在使用ChatGPT过程中&#xff0c;总感觉用chatgpt的效果没有那么好。经过多次使用和摸索&#xff0c;终于发现了问题&#xff0c;原来不是ChatGPT不好用&#xff0c;效果不好&#xff0c;而是因为我之前不会提问。 话不多说&#xff0c;给大家准备了30句ChatGPT提问公式 1、撰…

Python入门(四)列表(一)

列表&#xff08;一&#xff09; 1.列表简介1.1 什么是列表&#xff1f;1.2 访问列表元素 2.修改、添加和删除列表元素2.1 修改列表元素2.2 在列表中添加元素2.2 从列表中删除元素 作者&#xff1a;Xiou 1.列表简介 列表让你能够在一个地方存储成组的信息&#xff0c;其中可以…