Django ManyToManyField对多个类的多个属性

时间:2014-10-09 19:57:11

标签: django

给出以下课程:

class Person(models.Model):
    person_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=45)

class Person_Preference(models.Model):
    person_id = models.ForeignKey(Person, db_column='person_id')
    preference_type = models.CharField(max_length=255, blank=False)        
    preference_value = models.CharField(max_length=255, blank=False)

class Car(models.Model):
    car_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=45)

class Car_Feature(models.Model):
    car_id = models.ForeignKey(Car, db_column='car_id')
    feature_type = models.CharField(max_length=255, blank=False)        
    feature_value = models.CharField(max_length=255, blank=False)

表格示例

Person
---------
1 | Peter

Person_Preference
--------------------
1 | luxury | cooling
1 | safety | crash-proof
1 | luxury | heated seats

Car
----------
1 | Ford

Car_Feature
-----------------
1 | electronic | air-con
1 | verified | air-bag
1 | electronic | headed seats

问题

我想创建一个推荐类,将人的偏好与汽车特征联系起来,即:

class Recommendation(models.Model):
    preference_type = models.ManyToManyField('Person_Preference')
    preference_value = models.ManyToManyField('Person_Preference')
    feature_type = models.ManyToManyField('Car_Feature')
    feature_value = models.ManyToManyField('Car_Feature')

表格示例

Recommendation
---------
luxury | cooling | electronic | air_con

我意识到我不能这样做,因为在ManyToManyField Person_Preference和Car_Features中有两个引用相同类的属性。

这是否意味着没有办法与依赖于2个属性的类进行多对多关系?那么解决上述问题的唯一方法是为每个特定的preference_type和feature_type创建一个单独的类吗?

于2014年10月11日更新

为了更好地说明我的问题(我是Django的初学者,但更熟练的SQL),我正在尝试编写一个Django版本的SQL,它允许我使用preference_type作为第一个参数查找推荐表,和preference_value作为第二个参数:

SELECT *
FROM   Recommendation
WHERE  preference_type = 'luxury'
AND    preference_value = 'cooling'

我知道上面的内容可以使用Django的QuerySet过滤器来实现,虽然我试图利用多对多关系,因为看起来(对于我有限的模型知识),这是Django中正确的事情。虽然也许我对此错了?如果有人对如何创建Django模型有很好的参考,那么请告诉我。 (虽然我仍感到困惑,但我已多次阅读官方Django文档)

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:0)

您可以拥有多个具有相同类别的M2M,您只需要添加related_name参数,如下所示:

class Recommendation(models.Model):
    preference_type = models.ManyToManyField('Person_Preference', related_name='foo')
    preference_value = models.ManyToManyField('Person_Preference', related_name='bar')
    ...

修改

根据您的情况,只需这样做:

class Recommendation(models.Model):
    #I believe convention for m2m is to pluralize the field name
    preferences = models.ManyToManyField('Person_Preference')

您的查询将是:

Recommendation.objects.filter(preferences__type='luxury', preferences__value='cooling')

编辑2

这是一个更详细的例子:

型号:

class Preference(CommonModel):
    type = models.CharField(max_length=250, null=True, blank=True)
    value = models.CharField(max_length=250, null=True, blank=True)

class Recommendation(CommonModel):
    name = models.CharField(max_length=250, null=True, blank=True)
    preferences = models.ManyToManyField(Preference, null=True, blank=True)

    def __unicode__(self):
        return self.name

在Django shell中:

p1 = Preference.objects.create(type='foo', value='bar')
p2 = Preference.objects.create(type='foo')
p3 = Preference.objects.create(value='bar')

r1 = Recommendation.objects.create(name='foobar')
r1.preferences.add(p1)
r2 = Recommendation.objects.create(name='foo')
r2.preferences.add(p2)
r3 = Recommendation.objects.create(name='bar')
r3.preferences.add(p3)

>>> Recommendation.objects.filter(preferences__type='foo')
[<Recommendation: foobar>, <Recommendation: foo>]

>>> Recommendation.objects.filter(preferences__value='bar')
[<Recommendation: foobar>, <Recommendation: bar>]

>>> Recommendation.objects.filter(preferences__type='foo', preferences__value='bar')
[<Recommendation: foobar>]