我正在Django编写一个科学网络应用程序,处理抗体Fab片段的氨基酸序列,每个片段由一条重链和一条轻链组成。这些链中的每一个都由一系列氨基酸残基组成。
我的models.py
基本上是这样的:
from django.db.models import *
class Fab(Model):
name = CharField(max_length=30)
...
def __unicode__(self):
return self.name
class Chain(Model):
fab = ForeignKey(Fab)
TYPE_CHOICES = (
('L', 'light'),
('H', 'heavy'),
)
type = CharField(max_length=5)
...
class Residue(Model):
ch = ForeignKey(Chain)
...
因此,在将Fab输入数据库的过程中,我创建了2个链,为每个链分配type
和fab
个外键。然后,要在模板中使用这些,我使用以下视图,将每个链作为一个对象,并将其传递给独立于其Fab父对象的模板,这不是完全理想的。
def fab_detail(request, fab_id):
f = get_object_or_404(Fab, pk=fab_id)
h = get_object_or_404(Chain, fab=f, type='H')
l = get_object_or_404(Chain, fab=f, type='L')
return render_to_response('antibodies/fab_detail.html', {
'fab': f,
'light': l,
'heavy': h,
}, context_instance=RequestContext(request))
但是,我想:
{% for r in fab.light_chain.residue_set.all %}
循环链的残基。 我考虑过继承Chain
,但不确定如何实现类似的结果。我想出了一些类似的东西:
class Chain(Model):
# same as before, but without the fab ForeignKey field
...
class LightChain(Chain):
pass
class HeavyChain(Chain):
pass
class Fab(Model):
name = CharField(max_length=30)
light_chain = OneToOneField(LightChain)
heavy_chain = OneToOneField(HeavyChain)
...
class Residue(Model):
???
我遇到的主要问题是如何让LightChain
和HeavyChain
字段包含Residue
数据。具体来说,我将如何替换Residue类中的ch = ForeignKey(Chain)
?
非常感谢任何建议或参考。
答案 0 :(得分:0)
首先,你可以有一个元类,使字段在类型和链类型的组合上是唯一的。
class Chain(Model):
fab = ForeignKey(Fab)
TYPE_CHOICES = (
('L', 'light'),
('H', 'heavy'),
)
type = CharField(max_length=5, choices=TYPE_CHOICES)
class Meta:
unique_together = (
('type', 'fab'),
)
这样,你无法添加更多2,因为你只有两个选择。
class Residue(Model):
ch = ForeignKey(Chain)
看起来已经很好用了。
答案 1 :(得分:0)
keni的解决方案是我即将撰写的解决方案。
但是,我不认为“choices = TYPE_CHOICES”约束在任何级别都是强制执行的,它只是告诉Django在表单和管理员中使用“选择”菜单。所以理论上你可以有type ='R','W'或任何东西。顺便说一句,我认为你(jared)意味着max_length = 1。
另一种解决方案是简单地使用多表继承,而不是抽象基类,它们是{的两种不同形式{ {3}}。在这种情况下,您可以只使用ch = ForeignKey(Chain)
。但这可能是太多的开销:将创建三个表,一个用于Chain,一个用于Light,一个用于Heavy,后两个用于引用第一个,一个基本上不包含任何其他内容。如果您需要存储轻链或重链的特定信息,可能会很有趣。
第三种解决方案是:
class Fab(Model):
name = CharField(max_length=30)
light = OneToOneField(Chain, related_name="fab_as_light")
heavy = OneToOneField(Chain, related_name="fab_as_heavy")
通过这种方式,您可以非常轻松地完成fab.light和fab.heavy,并且可以实现唯一性。我很确定将两个OneToOneField用于同一型号是合法的。如果不是,您仍然可以使用外键并将其设置为“唯一”。 我认为第三个是你的解决方案。
为了完整起见,你需要:
class Residue(Model):
ch = ForeignKey(Chain)
Chain几乎是空的(只是id)。
答案 2 :(得分:0)
在尝试了几个不同的东西并且无法使用'my_chain.fab_as_light / heavy'语法之后,我目前的解决方案是在@Arthur的解决方案中使用变体,在那里我生成一些名为'type'和'的属性链模型中的fab',它是根据Fab对象的related_name值计算的。 (例如,在对Chain对象执行操作但不关心它是哪种类型的链接的函数中,这些将是有用的:my_chain.fab
返回轻链或重链的Fab对象。)< / p>
class Chain(Model):
# determine the type based on Fab related_name
def _get_type(self):
try:
if self.fab_as_light:
return 'L'
except:
try:
if self.fab_as_heavy:
return 'H'
except:
return None
type = property(_get_type)
# consolidate fab_as_light and fab_as_heavy into one property
def _get_fab(self):
try:
return self.fab_as_light
except:
try:
return self.fab_as_heavy
except:
return None
fab = property(_get_fab)
def __unicode__(self):
return "%s_%s" % (self.fab.name, self.type)
class Fab(Model):
name = CharField(max_length=30)
light = OneToOneField(Chain, related_name='fab_as_light')
heavy = OneToOneField(Chain, related_name='fab_as_heavy')
这可能不是最好的路线(它不是很优雅!),但它对我有用,所以我现在就一直用它。
感谢大家的投入。