1.このブログを書く目的
主な記録:
- djangoを使用して[1対多]のテーブル関係を作成する方法。
- そして、[1対多]のテーブル関係を通じて、対応する完全なビジネスオペレーションをどのように実行するか。
- djangoのどのコード構成を変更することにより、[one]テーブルのデータが削除されると、対応する[multi]テーブルのデータにどのような変更が加えられますか?
データテーブルAとデータテーブルBがあるとすると、テーブルAとテーブルBの間に4つのテーブル関係のうちの1つだけが存在する可能性があります。
- 表Aと表Bは独立しています。
- 表Aと表Bには、1対多の関係があります。表Bの表フィールドの値には、表Aの主キー値が格納されます。
- 表Aと表Bには1対1の関係があります。表Bでは、表フィールドの値に表Aの主キー値が格納されます。
- 表Aと表Bには、多対多の関係があります。中間表の2つの表フィールドには、表Aの主キー値と表Bの主キー値がそれぞれ格納されます。
2. [1対多]テーブル関係に対応するビジネス例
実生活では、多くの1対多のシナリオに遭遇します。
たとえば、最も一般的な例の1つは、次のとおりです。銀行カード情報を入力するときに、送信フィールド[銀行]のドロップダウンボックスから対応する銀行情報を選択します。
通常、2つのデータテーブルが作成されます。1つは銀行情報用、もう1つは銀行カード情報用です。
各銀行は複数の銀行カードに対応でき、各銀行カードは1つの銀行にのみ属することができます。
その場合、銀行と銀行カードは1対多の関係にあり、逆に、銀行カードと銀行は多対1の関係にあります。
完全な操作プロセスは、次のコンテンツで確認できます。
三、完全な操作プロセス
1.最初のステップ:[ helloworld / hello /models.py ]にモデルクラスを追加します
class Bank(models.Model):
# 银行信息
bank_name = models.CharField(max_length=50, verbose_name="银行名称")
city = models.CharField(max_length=30, verbose_name="所在城市")
point = models.CharField(max_length=60, verbose_name="所在网点")
class Meta:
verbose_name_plural = "银行"
def __str__(self):
return self.bank_name
class CardInfo(models.Model):
# 银行卡信息
card_id = models.CharField(max_length=30, verbose_name="卡号")
card_name = models.CharField(max_length=10, verbose_name="姓名")
card_info = models.ForeignKey(to=Bank, on_delete=models.CASCADE, verbose_name="选择银行")
class Meta:
verbose_name_plural = '银行卡信息'
def __str__(self):
return self.card_id
2.ステップ2:モデルクラスを[ helloworld / hello /admin.py ]に登録します
# 银行信息
class ControlBank(admin.ModelAdmin):
list_display = ["id", "bank_name", "city", "point"]
# 银行卡信息
class ControlCardInfo(admin.ModelAdmin):
list_display = ["id", "card_id", "card_name", "card_info"]
admin.site.register(models.Bank, ControlBank)
admin.site.register(models.CardInfo, ControlCardInfo)
3. 3番目のステップ:関連するステートメントを実行して、[ helloworld / ]のルートディレクトリにデータテーブルを生成します。
関連するステートメントと実行順序は次のとおりです。
3.1。まず、ステートメント[python manage.pymakemigrations]を実行します
3.2。最後に、ステートメント[python manage.pymigrate]を実行します
関連する結果は次のとおりです。
2つの対応するデータテーブルが生成されます
4.ステップ4:サービスを再起動します
5.ステップ5:管理者管理のバックグラウンドに正常にログインします
6.ステップ6:バックグラウンドで2つの銀行情報を追加します
7.ステップ7:バックグラウンドでの新規1銀行カード情報
4つの関連する知識ポイント
1.入力パラメーター値に対応するクラスForeignKeyの2つの必須パラメーターの簡単な分析
詳細:
クラスForeignKeyのクラス名から、ForeignKeyという単語の中国語の意味が[外部キー]であることが直感的にわかります。
1.1。最初のステップ:foreignKeyソースコードの[ __init__ ]メソッドの内容を確認します
class ForeignKey(ForeignObject):
"""
Provide a many-to-one relation by adding a column to the local model
to hold the remote value.
By default ForeignKey will target the pk of the remote model but this
behavior can be changed by using the ``to_field`` argument.
"""
descriptor_class = ForeignKeyDeferredAttribute
# Field flags
many_to_many = False
many_to_one = True
one_to_many = False
one_to_one = False
rel_class = ManyToOneRel
empty_strings_allowed = False
default_error_messages = {
'invalid': _('%(model)s instance with %(field)s %(value)r does not exist.')
}
description = _("Foreign Key (type determined by related field)")
def __init__(self, to, on_delete, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, to_field=None,
db_constraint=True, **kwargs):
try:
to._meta.model_name
except AttributeError:
assert isinstance(to, str), (
"%s(%r) is invalid. First parameter to ForeignKey must be "
"either a model, a model name, or the string %r" % (
self.__class__.__name__, to,
RECURSIVE_RELATIONSHIP_CONSTANT,
)
)
else:
# For backwards compatibility purposes, we need to *try* and set
# the to_field during FK construction. It won't be guaranteed to
# be correct until contribute_to_class is called. Refs #12190.
to_field = to_field or (to._meta.pk and to._meta.pk.name)
if not callable(on_delete):
raise TypeError('on_delete must be callable.')
kwargs['rel'] = self.rel_class(
self, to, to_field,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
parent_link=parent_link,
on_delete=on_delete,
)
kwargs.setdefault('db_index', True)
super().__init__(
to,
on_delete,
from_fields=[RECURSIVE_RELATIONSHIP_CONSTANT],
to_fields=[to_field],
**kwargs,
)
self.db_constraint = db_constraint
ソースコードのこの部分をインターセプトします。
def __init__(self, to, on_delete, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, to_field=None,
db_constraint=True, **kwargs):
ソースコードのこの部分から簡単にわかります:クラスForeignKeyがインスタンス化されるとき、2つの必須パラメーター[ to ]と[ on_delete ]をそれぞれ割り当てる必要があり、他の入力パラメーターの入力パラメーター値は通常、デフォルト値;
2.ステップ2:実際のビジネスコードに基づいて、必要なパラメーター[ to ]のパラメーター値と必要なパラメーター[ on_delete ]のパラメーター値を分析します。
実際のビジネスコードは次のとおりです。
class Bank(models.Model):
'''银行信息'''
bank_name = models.CharField(max_length=50,verbose_name="银行名称")
city = models.CharField(max_length=30,verbose_name="所在城市")
point = models.CharField(max_length=60,verbose_name="所在网点")
class Meta:
verbose_name_plural = "银行"
def __str__(self):
return self.bank_name
class CardInfo(models.Model):
'''银行卡信息'''
card_id = models.CharField(max_length=30, verbose_name="卡号")
card_name = models.CharField(max_length=10, verbose_name="姓名")
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="选择银行",)
class Meta:
verbose_name_plural = '银行卡信息'
def __str__(self):
return self.card_id
ビジネスコードのこの部分をインターセプトします。
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="选择银行",)
3.必要なパラメータのパラメータ値の理解[から]
パラメータ[ to ]の意味は次のとおりです。対応するテーブルに関連します(このテーブルは、1対多のテーブル関係にある1対多のテーブルです)。
パラメータ[ to ]のパラメータ値:[1対多のテーブル関係にある]モデルクラスに対応するモデルクラスのモデルクラス名のみである必要があります。
4.必要なパラメーターのパラメーター値の理解[ on_delete ]
パラメータ[ on_delete ]の意味は次のとおりです。クラスForeignKeyに関連付けられたテーブルの関係は1対多の2つのテーブルであり、1つのテーブルのテーブルデータが物理的に削除されると、マルチテーブルのテーブルは次のように物理的に削除されます。これらの対応する変更は、削除されたテーブルデータに関連付けられたテーブルデータに発生します。
パラメータ[ on_delete ]のパラメータ値は、次の6つのパラメータ値のうちの1つのみである必要があります。
models.CASCADE
models.PROTECT
models.SET_NULL
models.SET_DEFAULT
moels.SET(value)
models.DO_NOTHING
詳細:
- パラメータ[on_delete]の値が[models.SET_NULL]の場合:クラスForeignKeyの入力パラメータnullの値を[True]に設定する必要があります。
- パラメータ[on_delete]の値が[models.SET_DEFAULT]の場合:クラスForeignKeyの入力パラメータdefaultの入力パラメータ値を入力する必要があり、入力パラメータ値は正の整数のみにすることができます。
- パラメータ[on_delete]の値が[models.SET(value)]の場合:メソッドset()の入力パラメータ値の入力パラメータ値を入力する必要があり、入力パラメータ値は正の整数のみにすることができます。
- パラメータ[on_delete]の値は[models.CASCADE]で、これは頻繁に使用されるシーンです。
銀行がそのようなデータを表示するとします(後で関連するコピーライティングの説明の便宜上、このデータデータをAと名付けました):
cardinfoが2つのデータを表示するとします(後で関連するコピーライティングの説明を容易にするために、これら2つのデータをそれぞれデータBとデータCと名付けました):
各パラメータ値の具体的な機能は次のとおりです。
models.CASCADE:管理管理のバックグラウンドで、データAが物理的に削除されると、データAに関連付けられたデータBとデータCも物理的に削除されます。
models.PROTECTは:で管理データ管理の背景、Aは物理的に削除されるように、それは物理的に削除データに促すメッセージが表示されますB及びデータCの前に物理的にデータの消去Aを、そしてその後、後に物理的に削除データにしようと、物理的にデータの消去Bをし、データCが正常にAで、データAは物理的にすぐに削除できます。
models.SET_NULL:で管理データ管理背景、Aが物理的に削除され、値テーブルのフィールドの[ card_info_idの】データB及びデータC関連付けられたデータを用いてAが[から変わり25 ]乃至[ヌル]。
models.SET_DEFAULT:で管理データ管理の背景、Aは物理的に削除され、値テーブルのフィールドの[ card_info_id ]のデータB及びデータC関連付けられたデータを用いてAが[から変わり25に】入力パラメータデフォルトでクラスForeignKeyの入力パラメータ値(入力のパラメータ値のデフォルトのパラメータは正の整数であることができます)。
moels.SET:管理管理のバックグラウンドで、データAが物理的に削除されると、データBとデータAに関連付けられたデータCのテーブルフィールド[ card_info_id ]の値が[ 25 ]からメソッドset(のエントリに変更されます。)入力パラメータ値パラメータ値(入力パラメータ値入力パラメータ値のみが正の整数であることができます)。
models.DO_NOTHING:で管理データ管理背景、Aが物理的に削除され、各テーブルのフィールドのテーブルフィールド値データB及びデータC関連付けられたデータを用いてAが変わらない(で、後にデータAを物理的に削除され、データBおよびデータCはまったく影響を受けません) ;
これらの6つのパラメーター値に対応する特定のビジネスコードは次のとおりです(私はそれらをローカルでデバッグしました):
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="选择银行",)
card_info = models.ForeignKey(to=Bank,on_delete=models.PROTECT,verbose_name="选择银行",)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET_NULL,verbose_name="选择银行",null=True)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET_DEFAULT,verbose_name="选择银行",default=999999999)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET(value=7777777),verbose_name="选择银行",)
card_info = models.ForeignKey(to=Bank,on_delete=models.DO_NOTHING,verbose_name="选择银行",)