1. The purpose of writing this blog
Main record:
- How to create a [one-to-many] table relationship through django;
- And how to go through the corresponding complete business operations through the [one-to-many] table relationship;
- By modifying which code configuration in django, when the data in the [one] table is deleted, what changes will be made to the data in the corresponding [multi] table?
Suppose there is a data table A and a data table B , then only one of the four table relationships may exist between table A and table B :
- Table A and Table B are independent;
- Table A and Table B have a one-to-many relationship. The value of a table field in Table B stores the primary key value of Table A;
- Table A and Table B have a one-to-one relationship. In Table B, the value of a table field stores the primary key value of Table A;
- Table A and Table B have a many-to-many relationship. The two table fields of an intermediate table store the primary key value of Table A and the primary key value of Table B respectively;
2. [One-to-many] Business example corresponding to table relationship
We will encounter many one-to-many scenarios in real life.
For example, one of the most common examples is: when we fill in the bank card information, we will select the corresponding bank information from the drop-down box of the submission field [Bank];
Generally, two data tables will be built, one for bank information, and one for bank card information;
Each bank can correspond to multiple bank cards, and each bank card can only belong to one bank;
Then the bank and the bank card have a one-to-many relationship, on the contrary, the bank card and the bank have a many-to-one relationship;
The complete operation process can be seen in the following content;
Three, the complete operation process
1. The first step: Add a model class in [ 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. Step 2: Register the model class in [ 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. The third step: execute the relevant statements to generate the data table in the root directory of [ helloworld/ ]
The relevant statements and order of execution are:
3.1. First, execute the statement [python manage.py makemigrations]
3.2. Finally, execute the statement [python manage.py migrate]
The relevant results are as follows:
Two corresponding data tables will be generated
4. Step 4 : Restart the service
5. Step 5 : Successfully log in to the admin management background
6. Step 6 : Add 2 bank information in the background
7. Step Seven: New in the background 1 bank card information
Four, related knowledge points
1. A simple analysis of the two required parameters in the class ForeignKey corresponding to the input parameter values
detail:
From the class name of the class ForeignKey, we can intuitively know that the Chinese meaning of the word ForeignKey is [foreign key];
1.1. The first step: Look at the content in the [ __init__ ] method in the foreignKey source code
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
Intercept this part of the source code:
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):
It can be easily seen from this part of the source code: when the class ForeignKey is instantiated, the two required parameters [ to ] and [ on_delete ] must be assigned respectively, and the input parameter values of other input parameters generally keep the default values;
2. Step 2: Analyze the parameter value of the required parameter [ to ] and the parameter value of the required parameter [ on_delete ] based on the actual business code
The actual business code is as follows:
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
Intercept this part of the business code:
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="选择银行",)
3. Understanding of the parameter value of the required parameter [ to ]
The meaning of the parameter [ to ] is: related to a corresponding table ( this table is a one-to-many table in a one-to-many table relationship ) ;
The parameter value of the parameter [ to ]: it must only be the model class name of the model class corresponding to the [one in the one-to-many table relationship] model class;
4. Understanding of the parameter value of the required parameter [ on_delete ]
The meaning of the parameter [ on_delete ] is: the table relationship associated with the class ForeignKey is one-to-many two tables, when the table data of the one table is physically deleted, the table of the multi-table is physically deleted with these Corresponding changes will occur to the table data associated with the deleted table data;
The parameter value of the parameter [ on_delete ] must be only one of these 6 parameter values:
models.CASCADE
models.PROTECT
models.SET_NULL
models.SET_DEFAULT
moels.SET(value)
models.DO_NOTHING
detail:
- When the value of the parameter [on_delete] is [models.SET_NULL]: the value of the input parameter null in the class ForeignKey must be set to [True];
- When the value of the parameter [on_delete] is [models.SET_DEFAULT]: the input parameter value of the input parameter default in the class ForeignKey must be filled in and the input parameter value can only be a positive integer;
- When the value of the parameter [on_delete] is [models.SET(value)]: the input parameter value of the input parameter value in the method set() must be filled in and the input parameter value can only be a positive integer;
- The value of the parameter [on_delete] is [models.CASCADE], which is a frequently used scene;
Suppose that the bank shows such a piece of data ( we named this piece of data data A for the convenience of the description of the relevant copywriting later ) :
Suppose that cardinfo shows two pieces of data ( we named these two pieces of data as data B and data C , respectively , to facilitate the description of related copywriting later ) :
The specific functions of each parameter value are as follows:
models.CASCADE : In admin management background, when the data A are deleted physically, with the data A associated data B and data C will also be physically removed;
models.PROTECT : In the admin management background, when data A is to be physically deleted, it will be prompted to physically delete data B and data C before physically deleting data A , and then try to physically delete data after physically deleting data B and data C successfully At A , data A can be physically deleted immediately ;
models.SET_NULL : In the admin management background, when data A is physically deleted, the values of the table fields [ card_info_id ] of data B and data C associated with data A will change from [ 25 ] to [ Null ];
models.SET_DEFAULT : In the admin management background, when data A is physically deleted, the value of the table field [ card_info_id ] of data B and data C associated with data A will change from [ 25 ] to the input parameter default in the class ForeignKey The input parameter value ( the input parameter value of the default parameter can only be a positive integer ) ;
moels.SET : In the admin management background, when data A is physically deleted, the value of the table field [ card_info_id ] of data B and data C associated with data A will change from [ 25 ] to the entry in the method set() The input parameter value of the parameter value ( the input parameter value of the input parameter value can only be a positive integer ) ;
models.DO_NOTHING : In the admin management background, when data A is physically deleted, the table field value of each table field of data B and data C associated with data A remains unchanged ( that is, after data A is physically deleted, Data B and Data C are not affected at all ) ;
The specific business codes corresponding to these 6 parameter values are as follows ( I have debugged them locally ) :
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="选择银行",)