7

我正在为我开始的新 GeoDjango 项目编写测试。通常我使用Factory BoyFaker来创建模型实例进行测试。但是,我不清楚如何模拟 GeoDjango PointField 字段。在Spacialite中查看记录时,它显示为二进制 blob。

我对 GIS 的东西完全陌生,对如何在 Django 中为 PointFields 创建工厂有点困惑。

# models.py

from django.contrib.gis.db import models

class Place(models.Model):
    name = models.CharField(max_length=255)
    location = models.PointField(blank=True, null=True)

    objects = models.GeoManager()

    def __str__(self):
        return "%s" % self.name
# factories.py

import factory
from faker import Factory as FakerFactory
from . import models

faker = FakerFactory.create()

class PlaceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Place

    name = factory.LazyAttribute(lambda x: faker.name())
    #location = What do I do?
4

4 回答 4

11

我相信您需要为点实例创建自定义模糊属性。你能试试这个吗?现在我没有设置来运行它。

import random
from django.contrib.gis.geos import Point
from factory.fuzzy import BaseFuzzyAttribute

class FuzzyPoint(BaseFuzzyAttribute):
    def fuzz(self):
        return Point(random.uniform(-180.0, 180.0),
                     random.uniform(-90.0, 90.0))


class PlaceFactory(FakerFactory):
    name = factory.LazyAttribute(lambda x: faker.name())
    location = FuzzyPoint()
    class Meta:
        model = models.Place
于 2015-09-28T20:19:51.460 回答
11

正如Factory Boy 文档所说,Fussy 即将被弃用。

现在 FactoryBoy 包含 factory.Faker 类,这些内置的 fuzzer 中的大多数都被弃用,取而代之的是 Faker 等价物。

正如@Steven B所说,您必须创建自己的提供程序。我对他的代码做了一些更改,以使提供程序尽可能通用。

class DjangoGeoPointProvider(BaseProvider):

    def geo_point(self, **kwargs):
        kwargs['coords_only'] = True
        # # generate() is not working in later Faker versions
        # faker = factory.Faker('local_latlng', **kwargs)
        # coords = faker.generate()  
        faker = factory.faker.faker.Faker()
        coords = faker.local_latlng(**kwargs)
        return Point(x=float(coords[1]), y=float(coords[0]), srid=4326)

注意coords_only必须始终为真,因为我们只需要latlong值,没有任何额外的元数据。

注2generate()已弃用,请参阅相关答案

最后,它就像使用local_latlng 提供程序或任何内置提供程序一样。这是一个完整的例子:

class TargetFactory(factory.django.DjangoModelFactory):
    factory.Faker.add_provider(DjangoGeoPointProvider)

    class Meta:
        model = Target

    radius = factory.Faker('random_int', min=4500, max=90000)
    location = factory.Faker('geo_point', country_code='US')

注意:'US' 是默认的国家代码,在这个例子中可以省略,但是你可以在 Faker 文档中使用任何其他指定的国家代码。

于 2020-04-06T12:16:56.093 回答
2

Faker已经有了一些不错的地理特征。您可以创建自己的提供程序以使其适用于 Django,例如:

import factory
from faker.providers import BaseProvider
from django.contrib.gis.geos import Point

class DjangoGeoLocationProvider(BaseProvider):

    countries = ['NL', 'DE', 'FR', 'BE']

    # uses faker.providers.geo
    def geolocation(self, country=None):
        country_code = country or factory.Faker('random_element', elements=self.countries).generate()
        faker = factory.Faker('local_latlng', country_code=country_code, coords_only=True)
        coords = faker.generate()
        return Point(x=float(coords[1]), y=float(coords[0]), srid=4326)

这将为给定的国家/地区生成与 Django 兼容的积分。

注册后:

factory.Faker.add_provider(DjangoGeoLocationProvider)

您可以像任何内置提供程序一样在 DjangoModelFactory 中使用它:

from factory.django import DjangoModelFactory as Factory

class PlaceFactory(Factory):

    class Meta:
        model = Place

    location = factory.Faker('geolocation')
    # or
    another_location = factory.Faker('geolocation', country='NL')
于 2019-11-09T21:39:37.000 回答
0

您也可以直接设置该值。

import json

from factory import LazyAttribute
from factory.django import DjangoModelFactory


class PlaceFactory(DjangoModelFactory):
    static_location = "{'type': 'Point', 'coordinates': [1,1]}"
    random_location = LazyAttribute(lambda x: json.dumps({
        'type': 'Point',
        'coordinates': [random.uniform(-180.0, 180.0), random.uniform(-180.0, 180.0)]}
    ))
于 2021-02-23T10:07:49.793 回答