【问题标题】:10 sites through same codebase django MTI, ABCs or EAV10 个站点通过相同的代码库 django MTI、ABC 或 EAV
【发布时间】:2011-06-26 17:18:45
【问题描述】:

我有一个基于 django 的网上商店,在过去一年中一直在发展。目前大约有 8 个国家特定的商店在运行相同的代码库,外加一个 API,很快就会有一个 B2B 网站,还有几个国家要添加到列表中。

模型结构需要变化,尤其是地址模型、帐户模型等中的字段。

为了让事情变得更复杂一点,该站点正在运行 multidb,每个商店实例都在一个单独的数据库中。所以我有一种情况,我可能有一个基本的 ABC 模型,例如:

class Address(models.Model):
    class Meta:
        abstract=True

class Address_UK(Address):
    class Meta:
        db_table="shop_address"

class Address_IT(Address):
    class Meta:
        db_table="shop_address"
[etc]

然后在整个应用程序中编码以选择正确的模型,例如

if countrysettings.country == "UK":
    address = Address_UK()
elif countrysettings.country == "IT":
    address = Address_IT()

countrysettings.country 实际上是一个单独的设置类,它是 threading.local 的子类,并且国家代码也对应于 settings.DATABASES 中的一个键,由地理定位中间件处理程序配置。因此选择了正确的数据库,并且模型特定的变化反映在每个国家的数据库中。

但是这种方法存在问题:

  1. 它完全破坏了syncdb,对南方没有好处,除非我破解./manage.py,这样我就可以传入国家数据库,而不是需要中间件来设置它。

  2. 看起来很乱。如果 countrysettings.country == "xx": 代码就这么多,还有很多子类模型。

所以我想改用 django-eav,但我预见到管理中的问题,特别是字段排序。我知道 django-eav 将为管理员构建一个包含 eav 字段的模型表单,但我希望这些字段与国家/地区相关显示或隐藏。

我也考虑过有一个非抽象基类,例如地址,然后在需要时创建特定于国家/地区的变体(例如模型表继承)。但是后来我预见到基本模型会因每个模型变体的 one2one 字段而过载。但它会解决管理员的问题。

另一种选择可能是有一个额外的数据字段,并将其他字段序列化为 json 或 csv 或其他内容并将它们存储在此字段中。

【问题讨论】:

    标签: django models entity-attribute-value abc


    【解决方案1】:

    我可以考虑其他一些方法来解决您的问题。我认为选项 1 或选项 2 是最好的,但可能会选择选项 3。

    选项 1:一个代码库、一个数据库、一个 django 实例、站点框架:如果您实际上不需要为每个商店创建一个不同的数据库,请创建所有表和/或所有可能的字段,并巧妙地将sites framework 用于 condour 字段和模型。例如:为每个地址保留一个 address_type 字段等,并在每个站点的同一数据库上使用不同的字段(和表)。这使您的代码更加复杂,但大大简化了您的 IT。如果站点之间的代码更改非常少,请使用此选项。 (顺便说一句 - json 序列化是地址的一个不错的选择)。

    选项2:一个代码库,多个数据库,多个 django 实例: 使用相同的代码库设置多个站点,但要小心使用 python 的条件设置和动态特性来为每个站点生成不同的模型。每个站点都有自己的 settings-uk.py、settings-us.py 等,并且将拥有自己的数据库和使用动态模型的模型。例如:

    from django.conf import settings
    # ...
    class Address(models.Model):
         name = models.CharField(max_length=100)
         if settings.country == "US":
            state = models.CharField(max_length=2)
         else:
            country = models.CharField(max_length=100)
    

    此方法的其他可能技巧:通过设置启用/禁用应用程序;在 wsgi 脚本/manage.py 脚本中为应用程序制作自定义 Python 路径;使用 if settings.country=='us': import uk_x as x else: import us_x as x 。另见:http://code.flickr.com/blog/2009/12/02/flipping-out/

    选项 3:并行代码分支,许多 DB,许多 django 实例: 使用 git 保留代码的一些分支,并将它们彼此变基。需要更多的 IT 工作。如果您打算拥有许多数据库和许多服务器(以及许多开发人员?),您可能会发现这很有用。

    另一种选择:一个数据库,许多 django 实例每个实例的自定义 settings.py,没有站点框架。

    【讨论】:

      【解决方案2】:

      其实 EAV 可以解决您的问题。实际上,您可以使用 EAV 显示特定于当前对象的国家属性的字段。 这是一个例子

      class Country(models.Model):
          name = models.CharField(_("country"), max_length=50
      
      class Address(eav.models.BaseEntity):
          country = models.ForeignKey(Country, related_name="country_attrs")
      
          # EAV specific staff
          @classmethod
          def get_schemata_for_model(self):
              # When creating object, country field is still not set
              # So we do not return any country-specific attributes
              return AddressEAVSchema.objects.filter(pk=-1).all()
      
          def get_schemata_for_instance(self, qs):
              # For specific instance, return only country-specific attributes if any
              try:
                  return AdressEAVSchema.objects.filter(country=self.country).all()
              except:
                  return qs
      
      # Attributes now can be marked as belonging to specific country
      class AdressEAVSchema(eav.models.BaseSchema)
          country = models.ForeignKey(Country, related_name="country_attrs")
      
      # Rest of the standard EAV stuff    
      class AdressEAVChoice(eav.models.BaseChoice):
          schema = models.ForeignKey(AdressEAVSchema, related_name='choices')
      
      class AddressEAVAttribute(eav.models.BaseAttribute):
          schema = models.ForeignKey(AdressEAVSchema, related_name='attrs')
          choice = models.ForeignKey(AdressEAVChoice, blank=True, null=True)
      

      这里如何使用它:

      当您创建地址属性时,您现在还必须指定它们属于哪个国家/地区。

      现在,当您创建新的地址对象本身(例如在管理员中)、保存并返回编辑它时,您会看到与对象国家/地区相匹配的其他特定国家/地区的属性。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-08
        • 2012-07-07
        • 1970-01-01
        • 1970-01-01
        • 2012-09-03
        • 1970-01-01
        • 2014-08-27
        相关资源
        最近更新 更多