1. Purpose of writing this blog
Main records:
- How to create a [one to many] table relationship through django;
- And how to complete the corresponding business operations through the table relationship of [one to many];
- By modifying the code configuration in django, what changes will be made to the data of the corresponding [multiple] tables after the data of the [one] table is deleted?
Assuming that there is A data table A and A data table B, there may only be one of the following four table relationships in tables A and B:
- Tables A and B are independent;
- Table A and table B have A one to many relationship. There is A table field in table B that stores the primary key value of table A;
- Table A and table B have A one-to-one relationship. The value of A table field in table B stores the primary key value of table A;
- Table A and table B are many to many relationships. 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. Business example corresponding to the table relationship of [one to many]
We will encounter many one to many scenes in real life.
For example, the most common example is: when filling in the bank card information, we will select the corresponding bank information from the drop-down box in the submit 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 relationship between bank and bank card is one to many. On the contrary, the relationship between bank card and bank is many to one;
See the following contents for the complete operation process;
2. Complete operation process
2.1. Step 1: add a new model class in [helloworld/hello/models.py]
from django.db import models class Bank(models.Model): '''Bank information''' bank_name = models.CharField(max_length=50,verbose_name="Bank name") city = models.CharField(max_length=30,verbose_name="City") point = models.CharField(max_length=60,verbose_name="Network") class Meta: verbose_name_plural = "bank" def __str__(self): return self.bank_name class CardInfo(models.Model): '''Bank card information''' card_id = models.CharField(max_length=30, verbose_name="Card number") card_name = models.CharField(max_length=10, verbose_name="full name") card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="Select bank",) class Meta: verbose_name_plural = 'Bank card information' def __str__(self): return self.card_id
2.2. Step 2: register the model class in [helloworld/hello/admin.py]
from django.contrib import admin # Register your models here. from hello import models class ControlBank(admin.ModelAdmin): '''Bank information''' # Fields displayed list_display = ["id","bank_name","city","point"] class ControlCardInfo(admin.ModelAdmin): '''Bank card information''' # Fields displayed list_display = ["id","card_id","card_name","card_info"] admin.site.register(models.Bank,ControlBank) admin.site.register(models.CardInfo,ControlCardInfo)
2.3. Step 3: execute the relevant statements to generate the data table under the root directory of [helloworld /]
The related statements and order of execution are:
- First, execute the statement [python manage.py makemigrations]
- Finally, execute the statement [python manage.py migrate]
The relevant results are as follows:
- Two corresponding data tables will be generated
2.4. Step 4: restart the service
2.5. Step 5: successfully log in to admin management background
2.6. Step 6: add 2 bank information in the background
2.6. Step 7: add a bank card information in the background
3. Relevant knowledge points
3.1 The two required parameters in the ForeignKey class correspond to the detailed analysis of the input parameter values
Details:
- From the class name of ForeignKey, we can intuitively know that the Chinese meaning of ForeignKey is [foreign key];
3.1.1. The first step is to look at the [_init_] in the ForeignKey source code Content in method
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 seen from this part of the source code that when the class ForeignKey is instantiated, the two required parameters [to] and [on_delete] must be assigned values respectively, and the input parameter values of other input parameters generally remain the default values;
3.1.2. Step 2: analyze the parameter value of the required parameter [to] and the parameter value of the required parameter [on_delete] in combination with the actual business code
The actual business code is as follows:
class Bank(models.Model): '''Bank information''' bank_name = models.CharField(max_length=50,verbose_name="Bank name") city = models.CharField(max_length=30,verbose_name="City") point = models.CharField(max_length=60,verbose_name="Network") class Meta: verbose_name_plural = "bank" def __str__(self): return self.bank_name class CardInfo(models.Model): '''Bank card information''' card_id = models.CharField(max_length=30, verbose_name="Card number") card_name = models.CharField(max_length=10, verbose_name="full name") card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="Select bank",) class Meta: verbose_name_plural = 'Bank card information' def __str__(self): return self.card_id
Intercept this part of business code:
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="Select bank",)
3.1.2.1. Understanding of the parameter value of the required parameter [to]
The meaning of the parameter [to] is: associated with a corresponding table (this table is a one-to-one table in the one to many table relationship);
Parameter value of parameter [to]: must only be the model class name of the model class [one in one to many table relationship] corresponding to the [many in one to many table relationship] model class;
3.1.2.2. Understanding of the parameter value of the required parameter [on_delete]
The meaning of the parameter [on_delete] is: the table relationship associated through the class ForeignKey is one to many. When the table data of one table is physically deleted, the table data associated with these physically deleted table data in the tables of many tables will change accordingly;
The parameter value of the parameter [on_delete] must be only one of the six parameter values:
- models.CASCADE
- models.PROTECT
- models.SET_NULL
- models.SET_DEFAULT
- moels.SET
- models.DO_NOTHING
Suppose the bank has such A piece of data (we name this data data data A to facilitate the description of subsequent relevant documents):
Suppose cardinfo has two pieces of data (we name these two pieces of data as data B and data C respectively to facilitate the description of subsequent relevant documents):
The specific functions of each parameter value are as follows:
models.CASCADE: in the admin management background, when data A is physically deleted, data B and data C associated with data A will also be physically deleted;
models.PROTECT: in the admin management background, when data A is to be physically deleted, you will be prompted to physically delete data B and data C before data A can be physically deleted. Then, when data B and data C are successfully deleted and then try to physically delete data A, data A can be successfully deleted immediately;
models.SET_NULL: 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 [null];
models.SET_DEFAULT: 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 the input parameter value of input parameter default in class ForeignKey (the input parameter value of input parameter default can only be A positive integer);
moels.SET: 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 the input parameter value of the input parameter value in the method set() (the input parameter value of the input parameter value can only be A positive integer);
models. DO_ Notifying: in the admin management background, when data A is physically deleted, the table field values of each table field of data B and data C associated with data A remain 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 the six parameter values are as follows (I have passed the local debugging):
card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="Select bank",)
card_info = models.ForeignKey(to=Bank,on_delete=models.PROTECT,verbose_name="Select bank",)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET_NULL,verbose_name="Select bank",null=True)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET_DEFAULT,verbose_name="Select bank",default=999999999)
card_info = models.ForeignKey(to=Bank,on_delete=models.SET(value=7777777),verbose_name="Select bank",)
card_info = models.ForeignKey(to=Bank,on_delete=models.DO_NOTHING,verbose_name="Select bank",)