我有一个自定义类(可能很快就会发布),我想将其整齐地存储在Django中的某些模型中。
该类大致如下:
class BBOX(object):
def __init__(self, min_x, min_y, max_x, max_y, srs_code, **kwargs):
self.min_x = min_x
self.max_x = max_x
self.min_y = min_y
self.max_y = max_y
self._srs_code = get_srs_code(srs_code)
self._srs_identifier = 'EPSG:{}'.format(self.srs_code)
self._srs = SRS(self.srs_code)
该类具有许多属性和辅助函数,可用于安全处理基于地理空间的应用程序中的边界框对象。在代码中,我们安全地传递了这些信息,知道它们将易于使用并且可以与其余代码很好地交互。通常,除非绝对必须传递列表或类似内容(例如,当将值序列化为时),否则我们永远都不想在未由此类实例表示的代码中使用边界框。 JSON,YAML或类似的内容。
我们的几个Django模型具有与BBOX相关的值。当前,这些不同的模型都必须手动定义它们代表BBOX所需的字段。为了方便起见,我们在其中一些助手属性中添加了一些属性以转换为对象。例如:
class Layer(PolymorphicModel):
name = models.CharField(max_length=255, blank=True, null=True)
title = models.CharField(max_length=255, blank=True, null=True)
parent_layer = models.ForeignKey('self', blank=True, null=True)
min_x = models.FloatField()
min_y = models.FloatField()
max_x = models.FloatField()
max_y = models.FloatField()
srs_code = models.IntegerField()
@property
def bbox(self):
return BBOX(self.min_x, self.min_y, self.max_x, self.max_y, self.srs_code)
很明显,如果我们需要为每个可以具有BBOX的模型添加一组字段,那么这可能会导致很多代码重复。这可能使其难以维护且难以更改。
处理这样的事情的最佳方法是什么?我想本质上为BBOX创建一个新表:
class DjangoBbox(Model):
min_x = models.FloatField()
min_y = models.FloatField()
max_x = models.FloatField()
max_y = models.FloatField()
srs_code = models.IntegerField()
然后,我可以在需要的地方添加外键引用,但是这种想法对我来说却很奇怪。这个想法有天生的错误吗?我能想到的第一件事是,从理论上讲,多个键可以指向同一个DjangoBbox条目,并且对键的更改即使在无意间也会反映在这两个条目中。
答案 0 :(得分:1)
我看到了三种解决方案:
使用abstract model class:您可以创建一个抽象的BBox基类,该基类在每次创建模型时都继承自。只需将其他字段添加到您的子类中即可。因此,假设有一个抽象的BBOXModel
类:
class Layer(BBOXModel):
name = models.CharField(max_length=255, blank=True, null=True)
title = models.CharField(max_length=255, blank=True, null=True)
parent_layer = models.ForeignKey('self', blank=True, null=True)
layer = Layer.objects.first()
layer.min_x # returns the min_x field
layer.bbox # returns the bbox property from `BBOXModel`
layer.bbox = myBbox # if you also create a setter for this property
Multi-table inheritance也可能会起作用,因此您的模型继承自具体的BBox模型:这将自动创建一对一的关系。它还使用所有边界框创建一个单独的表(因此您可以单独查询它),但是每个表都仅附加到一个子模型实例,该子模型实例可以是不同的类型。同样,父类上的所有属性和方法都可以像子类上期望的那样工作。上面的代码示例是相同的,除了因为您现在有了具体的BBOXModel
,您还可以执行以下操作:
bbox = BBOXModel.objects.first()
bbox.layer # works if this bbox "is part of a" Layer, otherwise it will throw an AttributeError
最后,您可以创建一个完整的custom field type:它可以在模型中容纳适当的BBOX
:该字段本身就是您已经拥有的BBOX
,所以当说layer.bbox
,就像您已经习惯的那样,这将是一个完整的python BBOX
对象。它需要确定如何在数据库中编码BBOX
。链接中的示例(一手牌)可能会有所帮助。就个人而言,如果使用PostgreSQL,我将使用JSONField
作为基础数据库字段(继承自JSONField
)。您可能只需要定义to_python
和get_prep_value
,与JSON进行相互转换并调用super()
,让JSONField
处理它在数据库中的表示方式。这样您就可以像这样定义您的类:
class Layer(PolymorphicModel):
name = ...
...
bbox = BBOXField()
使用所有这三个选项,您可以通过将对BBOX
对象的处理封装在类(或字段)中来完全重用已经拥有的BBOX
类。您应该最终可以只为模型实例分配一个BBOX
,并且当从db获取模型实例时,获取其bbox
属性,该属性将返回BBOX
。