在Django管理界面字段中添加自定义JS

8 投票
2 回答
13137 浏览
提问于 2025-04-15 16:30

在一个Django应用中,我有一个这样的模型:

class Appointment(models.Model):
    #some other fields
    #address fields
    zipcode=models.CharField(max_length=5)
    address=models.CharField(max_length=120)
    latitude=models.FloatField()
    longitude=models.FloatField()

当我渲染一个预约时,我只是把一个标记放在指定的经度和纬度位置,并用地址作为文本,但我需要经度和纬度来做到这一点。

目前,经度和纬度需要在后台手动输入,但打开谷歌地图或开放街图,搜索地址并输入经度和纬度,这些工作不应该由人手动完成,所以我想通过谷歌地图的API来获取这些信息(这个过程叫做地理编码)。

理想情况下,我希望在地址旁边有一个“获取坐标”的按钮,按下后会开始一个地理编码请求,当地址明确时,会自动填写经度和纬度,并展示一个地图,用户点击正确的标记时就能填写坐标。

我知道怎么做,但不太确定该如何把这些代码和标记放到后台管理界面中。

我考虑过一些方法,但觉得这些方法不太自然,或者对这么简单的任务来说工作量太大:

  • 把代码放在地址字段描述中,在从 admin.ModelAdmin 继承的类里的 field_options
  • 把所有与地址相关的内容放在一个单独的模型中,并使用一个自定义的 form(还需要一个单独的模板)
  • 创建一个地址选择器小部件
  • 使用GeoDjango

2 个回答

20

这里主要讨论的是客户端的标记和客户端的JavaScript。既然如此,使用一个专门处理这些内容的工具似乎是个不错的选择。我还建议你可以制作一个自定义的管理小部件。我自己也用过这种方法。根据客户端标记的大小,你甚至可以利用Django模板来渲染这个小部件。

另外,你也可以写一些不干扰页面的JavaScript,在页面加载后重新渲染那部分内容。用这种方法,你只需要在管理模型中用class Media:来包含那个JavaScript文件就可以了。

这更像是伪代码,但能让你明白大概意思:

admin.py

class AppointmentAdmin(admin.ModelAdmin):
    # ...

    class Media:
        from django.conf import settings
        media_url = getattr(settings, 'MEDIA_URL', '/media')
        js = [ media_url+'/admin/long-lat-render.js', ]

long-lat-render.js

// Written for jQuery
$(function(){
    // on page load...

    $('#_LongitudeTag').html('');

    var getCoordButton = $('<button id="get-coords"></button>');
    $('#_LongitudeTag').append(getCoordButton);

    addGMap($('#_LongitudeTag').get(0));
});

function addGMap(element) {
   // do whatevers
}
4

有几种方法可以做到这一点。你自己已经提到了一些。

一种选择是覆盖你管理后台的保存页面模板,然后在模板中添加所需的代码。你可以通过在你的ModelAdmin类中使用一个内部的Media类来添加所需的媒体文件、JavaScript、CSS等。这个Media类有两个不同的属性,一个是包含CSS样式表的元组,另一个是包含JavaScript文件的元组。

我个人觉得,在这种情况下,最好的选择是使用一个自定义的地址选择器小部件,就像你在不想采用的方法列表中提到的那样。

撰写回答