Python 将Factory Boy与GeoDjango点域一起使用

Python 将Factory Boy与GeoDjango点域一起使用,python,django,gis,geodjango,factory-boy,Python,Django,Gis,Geodjango,Factory Boy,我正在为一个新的GeoDjango项目编写测试。通常我使用和来创建模型实例进行测试。但是,我不清楚如何模拟GeoDjango点域字段。当查看中的记录时,它显示为二进制blob 我对GIS完全不熟悉,对于如何在Django为点域创建工厂有点困惑 #models.py 从django.contrib.gis.db导入模型 上课地点(模型。模型): name=models.CharField(最大长度=255) location=models.PointField(blank=True,null=Tr

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

我对GIS完全不熟悉,对于如何在Django为点域创建工厂有点困惑

#models.py
从django.contrib.gis.db导入模型
上课地点(模型。模型):
name=models.CharField(最大长度=255)
location=models.PointField(blank=True,null=True)
objects=models.GeoManager()
定义(自我):
返回“%s”%self.name
#factories.py
进口工厂
从冒牌货进口工厂作为冒牌货工厂
从…起导入模型
faker=FakerFactory.create()
类PlaceFactory(factory.django.DjangoModelFactory):
类元:
model=models.Place
name=factory.LazyAttribute(lambda x:faker.name())
#位置=我该怎么做?

我认为您需要为点实例创建自定义模糊属性。你能试试这个吗?现在,我没有运行所有程序的设置

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
已经有了一些不错的地理特征。您可以创建自己的提供程序以使其适用于Django,例如:

进口工厂
从faker.providers导入BaseProvider
从django.contrib.gis.geos导入点
DjangoGeoLocationProvider类(BaseProvider):
国家=['NL','DE','FR','BE']
#使用faker.providers.geo
def地理位置(自身、国家/地区=无):
country\u code=country或factory.Faker('random\u element',elements=self.countries)。generate()
faker=工厂.faker('local\u latlng',country\u code=country\u code,coords\u only=True)
coords=faker.generate()
返回点(x=float(坐标[1]),y=float(坐标[0]),srid=4326)
这将为特定国家生成Django兼容点

注册后:

factory.Faker.add\u提供程序(DjangoGeoLocationProvider)
您可以在DjangoModelFactory中像任何内置提供程序一样使用它:

从factory.django导入DjangoModelFactory作为工厂
类别工厂(工厂):
类元:
模型=地点
位置=factory.Faker(‘地理位置’)
#或
另一个位置=factory.Faker('geolocation',country='NL')
福西就要像他说的那样了

现在FactoryBoy包含了factory.Faker类,这些内置模糊器中的大多数都被弃用,取而代之的是Faker类

如上所述,您必须创建自己的提供者。我对他的代码做了一些修改,以使提供者尽可能通用

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\u only
必须始终为true,因为我们只需要
lat
long
值,而不需要任何额外的元数据

注意2
generate()
已弃用,请参阅

最后,这就像使用
本地\u latlng
或任何内置提供者一样。以下是一个完整的示例:

类TargetFactory(factory.django.DjangoModelFactory):
factory.Faker.add_提供程序(DjangoGeoPointProvider)
类元:
模型=目标
半径=工厂假货('random_int',最小值=4500,最大值=90000)
地点=工厂。伪造者('geo_point',国家代码='US')

注意:“US”是默认的国家代码,在本例中可以省略,但您可以在Faker doc中使用任何其他指定的国家代码。

您也可以直接设置该值

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)]}
    ))

如果您没有固定在Factory Boy上,请为model mommy签出此扩展(到目前为止,是我创建测试记录的首选库):