使用Factory Boy和GeoDjango PointFields

时间:2015-09-28 17:47:32

标签: python django gis geodjango factory-boy

我正在为我刚开始的新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 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:7)

正如deprecated所说的那样,挑剔即将成为Factory Boy documentation

现在FactoryBoy包含了factory.Faker类,因此大多数内置的模糊器均已弃用,以支持其Faker等效项。

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

class DjangoGeoPointProvider(BaseProvider):

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

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

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

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')

注意:“美国”是默认的国家/地区代码,在此示例中可以省略,但是您可以在Faker文档中使用任何其他指定的国家/地区代码。

答案 2 :(得分:1)

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')

答案 3 :(得分: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)]}
    ))