Django: “Soft” ForeignField without database integrity checks

前端 未结 6 1315
南旧
南旧 2021-02-05 17:05

I have a Django project that has multiple django \"apps\". One of them has models to represent data coming from an external source (I do not control this data).

I want m

6条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-05 17:44

    I tried something similar to Izz ad-Din Ruhulessin's suggestion but it didn't work because I have columns other than the "fake FK" column. The code I tried was:

    class DynamicPkg(models.Model):
        @property
        def cities(self):
            return City.objects.filter(dpdestinations__dynamic_pkg=self)
    
    
    class DynamicPkgDestination(models.Model):
        dynamic_pkg = models.ForeignKey(DynamicPkg, related_name='destinations')
        # Indexed because we will be joining City.code to
        # DynamicPkgDestination.city_code and we want this to be fast.
        city_code = models.CharField(max_length=10, db_index=True)
    
    
    class UnmanagedDynamicPkgDestination(models.Model):
        dynamic_pkg = models.ForeignKey(DynamicPkg, related_name='destinations')
        city = models.ForeignKey('City', db_column='city_code', to_field='code', related_name='dpdestinations')
    
        class Meta:
            managed = False
            db_table = DynamicPkgDestination._meta.db_table
    
    
    class City(models.Model):
        code = models.CharField(max_length=10, unique=True)
    

    and the errors I got were:

    Error: One or more models did not validate:
    travelbox.dynamicpkgdestination: Accessor for field 'dynamic_pkg' clashes with related field 'DynamicPkg.destinations'. Add a related_name argument to the definition for 'dynamic_pkg'.
    travelbox.dynamicpkgdestination: Reverse query name for field 'dynamic_pkg' clashes with related field 'DynamicPkg.destinations'. Add a related_name argument to the definition for 'dynamic_pkg'.
    travelbox.unmanageddynamicpkgdestination: Accessor for field 'dynamic_pkg' clashes with related field 'DynamicPkg.destinations'. Add a related_name argument to the definition for 'dynamic_pkg'.
    travelbox.unmanageddynamicpkgdestination: Reverse query name for field 'dynamic_pkg' clashes with related field 'DynamicPkg.destinations'. Add a related_name argument to the definition for 'dynamic_pkg'.
    

    However I did come up with a working solution by using a proxy model. I did still have to hack around some Django validation that prevents fields from being included in proxy models:

    class DynamicPkg(models.Model):
        @property
        def cities(self):
            return City.objects.filter(dpdestinations__dynamic_pkg=self)
    
    
    
    def proxify_model(new_class, base):
        """
        Like putting proxy = True in a model's Meta except it doesn't spoil your
        fun by raising an error if new_class contains model fields.
        """
        new_class._meta.proxy = True
        # Next 2 lines are what django.db.models.base.ModelBase.__new__ does when
        # proxy = True (after it has done its spoil-sport validation ;-)
        new_class._meta.setup_proxy(base)
        new_class._meta.concrete_model = base._meta.concrete_model
    
    
    class DynamicPkgDestination(models.Model):
        dynamic_pkg = models.ForeignKey(DynamicPkg, related_name='destinations')
        # Indexed because we will be joining City.code to
        # DynamicPkgDestination.city_code and we want this to be fast.
        city_code = city_code_field(db_index=True)
    
    
    class ProxyDynamicPkgDestination(DynamicPkgDestination):
        city = models.ForeignKey('City', db_column='city_code', to_field='code', related_name='dpdestinations')
    
    
    proxify_model(ProxyDynamicPkgDestination, DynamicPkgDestination)
    
    
    class City(models.Model):
        code = models.CharField(max_length=10, unique=True)
    

提交回复
热议问题