Django Framework 4: ORM Advanced Operations - Definition and multi-table operations

Relationship Model Description:
UserInfo: employee information table, Dept: Department, JobLevel: Level

111.PNG

First, many relationship

    1, using ForeignKey definition table being associated with the primary field must be unique attribute or primary_key

            ForeignKey, use ForeignKey fields is a query object, use. To research the child table data

            Main table: to the table, the child table, table definitions ForeignKey

            ** Note that if the UserInfo table records exist, migrate the time will complain

                1) first master data table entry, then the ForeignKey disposed in deafult

                2) A null is set to True ForeignKey


parameter Explanation Remark
to

Main Table Name: Required

Yes omitted to

Example:

'Group'或to=‘Group’

to_feild

Primary table associated fields: must be unique or primarykey

Primarykey 1, is omitted, automatic association primary table

2, the primary key field associated with the specified

3, sub-table associated field name automatically generated

Example:

s=models.ForeignKey('Salary')

Subtable field generated automatically s_id

s: ForeignKey defined name

_id: Fixed

related_name

Foreign key definition to an external query methods, alternative _set, _set failure

As a method of use

related_name='r'

obj.r.filter()

on_delete

Delete the data after the main table, the child table to do anything, the Required!

CASCADE: This value is set, a cascade delete.
PROTECT: This setting value is integrity errors will be reported.
SET_NULL: This value is set, put foreign key is set to null, provided that allow to null.
SET_DEFAULT: This value is set, the default value will set the foreign key.
SET (): This value is set, the value will call out, may be a function.


default

Default foreign key: If the recording child table reference to the following three

1, if not specified, a prompt to run makemigrateion

2, first built the primary table record, then ForeignKey, or does not match the foreign key constraint

3, may be provided to null null = True


related_query_name

Given primary table, the sub-queries by related_query_name table field, the master table is returned objects queryset


To define a foreign key field in the outer query, use the filter in

The sub-table is defined: related_query_name = 'r'


Group.objects.fileter(r__name='sa')

Sub-table is returned by the corresponding Group name = sa

limit_choices_to Unknown origin
parent_link Unknown origin
db_constraint Unknown origin

        Table Structure Code

from django.db import models
class UserInfo(models.Model):
    # 自动生成id,并设置为主键
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    
    # 定义关系,只写模型名,默认找JobLevel的primarykey字段
    # level = models.ForeignKey('JobLevel',on_delete=SET_DEFAULT,default='1')
    
    # to_field可以指定primarykey或unique字段,副表自动生成的依然是level_id字段
    # level = models.ForeignKey('JobLevel', to_field='id')
    
    level = models.ForeignKey('JobLevel', to_field='id', related_name='r_method',
                   related_query_name='r_query', on_delete='SET_NULL',null=true)
    

class JobLevel(models.Model):
    # 自动生成id,并设置为主键
    name = CharField(max_lengh=32)
    salary = IntegerField()
    
    
# 添加:level可以赋对象值。
models.UserInfo.objects.create(username='root4',password=1111,
                               level=models.JobLevel.objects.filter(level='SS1').first()
                               )

        查询:

            _set,主表操作副表记录,须first或get获取单一对象,Queryset列表不能使用_set

# -副表->主表
u=models.UserInfo.objects.filter(id=1).first()        # 使用filter的结果是queryset对象,所以加first只取一个Models对象,方便操作。
u.level                                               # .定义的外键名,结果是JobLevel对象
u.level.salary                                        # .定义的外键名.主表字段,结果是查询主表的对应字段值 
# 使用双下划线__查询:
u=models.UserInfo.objects.filter(level__salary=10000) # 通过外键level__salary,查询工资是10000的所有用户

    
# -通过主表查副表:
    #使用related_name查询
s=j.r_method.all()                                    # 通过related_name查询,结果是queryset类型
    #使用_set,需要把ForeignKey里面的related_name删掉。否则报错。
s=j.userinfo_set.all()                                # 结果和上面一样
    #使用related_query_name查询
s=models.JobLevel.objects.filter(r_query__name='root')    # root对应的joblevel,返回的是QuerySet对象
    
# -通过副表__查询主表:
s=models.UserInfo.objects.filter(joblevel__name='s1')     # 查询S1职位对应的所有用户。

    修改

        update基于字段修改

        add基于对象更改,自动找到关联外键字段

        对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

        一对多,对于.remove和.add只能在_set情况下使用,通过主表改副表里用,remove:清空字段,字段必须null=True

# 修改1:使用queryset对象更新副表
j=models.JobLevel.objects.filter(id=2).first()
u=models.UserInfo.objects.filter(id__lt=10)           # 注意获取到的是queryset对象
u.update(level=j)                                     # 因为level字段是一个对象,所以把查询到的对象j赋值给level
# 修改2:使用obj更新副表
for u_obj in u:                                       # 直接给UserInfo表赋值
    u_obj.update(level_id=j.id)
    # 或:u_obj.update(level_id=2)

# 修改3:使用_set修改,通过主表对象修改副表
j.userinfo_set.add(*u)                                # 使用*u把对象j传给QuerySet对象
j.userinfo_set.add(obj_u)                             # 把j传递给obj_u的models对象。

    删除:

        是指删除副表关联字段的值

# j.userinfo_set.remove(*u)
# 这个是坑,*u里的所有对象必须都关联id=2的对象,如果有关联id=3的,会报错!!!!!

          

    2、_set,   主表操作副表记录,须first或get获取单一对象,Queryset列表不能使用_set

level_obj = models.JobLevel.objects.filter(level='SS1').first()    # 必须first或get获取单一对象,Queryset列表不能使用_set


二、多对多关系

    表结构代码:

        1、使用ManyToManyField自动生成中间表结构

            优点:表自动维护,缺点:无法直接对表进行操作。

        默认中间表名:应用_表1_表1定义的外键名,例:ormtest_userinfo_dept_obj

class UserInfo(models.Model):
    # 自动生成id,并设置为主键
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()      
    level = models.ForeignKey('JobLevel', to_field='id', related_name='r_method',
                   related_query_name='r_query', on_delete='SET_NULL',null=true)
    dept_obj = models.ManyToManyField('Dept')
    
class Dept(models.Model):
    name = models.CharField(max_length=50)
    code = models.CharField(max_length=50, unique=True)

        操作:

"""ManyToManyField"""
# 创建Dept表记录
models.Dept.objects.create(name='开发部',code='KF0001')
models.Dept.objects.create(name='总务部',code='ZW0002')
models.Dept.objects.create(name='采购部',code='CG0003')

# 添加1,通过对象,add添加
u1 = models.UserInfo.objects.filter(name='root').first()
d1 = models.Dept.objects.filter(name='开发部').first()
u1.dept_obj.add(d1)

# 添加1-2,通过对象,添加多个
u1 = models.UserInfo.objects.filter(name='user')
d1 = models.Dept.objects.filter(name='开发部').first()
d1.userinfo_set.add(*u1)        # 把u1所有的对象都和d1建立关联

# 添加2,通过id,add添加
u1 = models.UserInfo.objects.filter(name='root1').first()
u1.dept_obj.add(*[1, 3])      # 添加多个
u1.dept_obj.add(2)        # 添加一个
# 添加3,通过对象,使用_set 返向add添加
u1 = models.UserInfo.objects.filter(name='root').first()
d1 = models.Dept.objects.filter(name='开发部').first()
d1.userinfo_set.add(u1)

# 查询1,使用__查副表字段:
u3 = models.UserInfo.objects.filter(dept_obj__name='开发部').all()
# 查询2,使用_set查询
d3 = models.Dept.objects.filter(name='开发部').first()
u3 = d3.userinfo_set                    # 与查询1的u3一样


# 删除1,移除field值,从中间表删除整条记录
u2 = models.UserInfo.objects.filter(name='root').first()
d2 = models.Dept.objects.filter(name='总务部').first()
d2.userinfo_set.remove(u2)

# 删除2,清空对应的中间表记录
d2.userinfo_set.clear()

# 使用.set修改关联值:通过中间表ID可以判断出来,set原理是先删除后建立
# 注意事项:
    # 1、u2对应中间表多个记录,set把所有对应记录全删掉
    # 2、set只创建对应参数的记录
u2.dept_obj.set('3')        # 只创建一个对应id为3的记录
u2.dept_obj.set(['2','1'])  # 列表前不加*

        2、使用Foreignkey实现多表关联

            优点:可以自定义中间表结构。

class UserInfo(models.Model):
    # 自动生成id,并设置为主键
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()      
    department = models.ManyToManyField
    dept_obj = models.ManyToManyField('Dept')


class Dept(models.Model):
    name = models.CharField(max_length=50)
    code = models.CharField(max_length=50, unique=True)

class UserInfo_To_Dept(models.Model):
    userinfo = models.ForeignKey('UserInfo')
    dept = models.ForeignKey('Dept')
    level = models.CharField(max_length=50)        # 自定义的字段




Guess you like

Origin blog.51cto.com/yishi/2440334