Tri*_*lla 4 html python sqlite django django-models
我有一个 Django 应用程序,需要按位置过滤用户(显示在登录用户给定距离内的用户)。
现在我能够latitude and longitude使用 HTML5捕获登录用户的坐标并将它们保存到Location我的 SQLite 后端的表中。
我有GeoIP2名单与city和country在我的项目文件夹中,我不知道我该如何使用他们,但他们似乎是一个不错的选择,因为他们采取lat和lon坐标,并产生出一个位置。
我知道这里有几个选项,例如point从lat lon坐标中创建一个值,然后也许可以按半径过滤?等等,5公里,10公里,15公里?
我对所有这些都比较陌生,这就是为什么我要求一个干净的最小解决方案。
我不想使用 PostGres、GIS、GeoDjango。
如果有人使用 Sqlite 和可能的 geoip2 列表有一个简单的解决方案,我将非常感谢您分享它!
模型.py
class Location(models.Model):
latitude = models.DecimalField(max_digits=19, decimal_places=16)
longitude = models.DecimalField(max_digits=19, decimal_places=16)
user = models.OneToOneField(User, on_delete=models.CASCADE, null=False, related_name='loc')
def __str__(self):
return f'{self.user}\'s location'
@login_required
def insert(request):
location = Location(latitude=request.POST['latitude'],
longitude=request.POST['longitude'], user = request.user)
location.save()
return JsonResponse({'message': 'success'})
def location_view(request):
queryset = User.objects.annotate(
radius_sqr=pow(models.F('loc__latitude') -
request.user.loc.latitude, 2) + pow(models.F('loc__longitude') -
request.user.loc.longitude, 2)
).filter(
radius_sqr__lte=pow(radius_km / 9, 2)
)
return django.shortcuts.render_to_response(request, context, 'connect/home.html')
Run Code Online (Sandbox Code Playgroud)
位置 page.html 示例
{% for user in location %}
<h5><b>{{ user.first_name }} {{ user.last_name }}</b></h5>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
首先,如果您的用户只有一个位置,则更有可能使用 OneToOneField 而不是外键。在用于增强查询构建的任何关系中放置“related_name”参数也是一个好主意。像这样:
class Location(models.Model):
lat = models.DecimalField(max_digits=19, decimal_places=16)
lon = models.DecimalField(max_digits=19, decimal_places=16)
user = models.OneToOneField('User', on_delete=models.CASCADE, related_name='loc')
def __str__(self):
return f'{self.user}\'s location'
Run Code Online (Sandbox Code Playgroud)
请注意, null=False 是相关字段的默认值。现在我们需要计算半径的平方作为纬度和经度之间差异的平方和。对于每一行的计算,我们可以使用 django.models.F 类在 annotate 或 filter 方法中使用。最后,我们在 filter lte 方法中使用计算值(按半径平方过滤很重要)。对于 request.user 它将看起来像:
from django.db.models import F
from django.shortcuts import render_to_response
def location_view(request):
radius_km = request.data.get('radius', 0)
queryset = User.objects.annotate(
radius_sqr=pow(models.F('loc__latitude') -
request.user.loc.latitude, 2) + pow(models.F('loc__longitude') -
request.user.loc.longitude, 2)
).filter(
radius_sqr__lte=pow(radius_km / 9, 2)
)
context = dict(location=queryset)
return render_to_response('connect/home.html', context)
Run Code Online (Sandbox Code Playgroud)
radius在 javascript 函数的请求 POST 负载中作为数字放置,这将请求 POST 到location_view.
请注意,此计算在远距离上会不准确,而在近极地区会更不准确。在半径附近抓住这个9系数?它是赤道上一度的千米数)。为了更准确,我们需要更深入地学习数学并根据用户的纬度使用计算出的系数。
需要更高的准确性?只需使用 GeoDjango 或像谷歌地理编码这样的侧面 API。