簡體   English   中英

Django模型需要兩個相關字段之一:我應該使用oneToOneField嗎?

[英]Django model needs one each of two related fields: should I use oneToOneField?

我正在Django中編寫一個科學的Web應用程序,處理抗體Fab片段的氨基酸序列,每個片段都恰好由一條重鏈和一條輕鏈組成。 這些鏈中的每條鏈均由一系列氨基酸殘基組成。

  • 1號廠房
    • 輕鏈
      • 殘渣1
      • 殘渣2
      • ...
    • 重鏈
      • 殘渣1
      • 殘渣2
      • ...
  • 晶圓廠2
    • 等等...

我的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))

但是,我想:

  1. 有一個更好的方法可以引用模板中的輕鏈或重鏈,例如,用{% for r in fab.light_chain.residue_set.all %}環回鏈的殘基。
  2. 確保每個Fab只有1條輕鏈和1條重鏈

我已經考慮過將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):
    ???

我遇到的主要問題是如何獲取LightChainHeavyChain字段以包含Residue數據。 具體來說,在Residue類中,用什么替換ch = ForeignKey(Chain)

任何建議或參考將不勝感激。

例如,您可以具有一個meta類,以使字段在類型和鏈類型的組合上唯一。

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)

看起來和上面使用的一樣好。

keni的解決方案就是我要寫的解決方案。

但是,我認為“ choices = TYPE_CHOICES”約束不會在任何級別強制執行,它只是告訴Django在表單和管理中使用“選擇”菜單。 因此,理論上您可以輸入type ='R','W'或其他任何內容。 順便說一句,我認為您(受刺激)的意思是max_length = 1。

另一個解決方案是像您一樣簡單地使用多表繼承 ,而不是抽象基類 ,后者是模型繼承的兩種不同形式。 在這種情況下,您只需擁有ch = ForeignKey(Chain) 但這可能會產生太多開銷:將創建三個表,一個用於鏈表,一個用於輕表,一個用於重表,后兩個表引用第一個表,一個基本不包含其他內容。 如果您需要存儲輕鏈或重鏈的特定信息,可能會很有趣。

第三種解決方案是這樣做:

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)。

在嘗試了幾種不同的方法並且無法使用'my_chain.fab_as_light / heavy'語法后,我當前的解決方案是使用@Arthur解決方案的一種變體,在其中我生成了一些稱為'type'和'fab'的屬性。 Chain模型,基於Fab對象的related_name值計算得出。 (例如,在對Chain對象執行操作但不關心鏈是哪種類型的函數中,這些函數將很有用: my_chain.fab返回輕鏈或重鏈的Fab對象。)

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')

這可能不是最好的路線(並不完全是優美的路線!),但是它對我有用,所以我現在就繼續使用。

謝謝大家的投入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM