Django模型的高级:模型迁移与反向迁移、模型关系(一对一模型、一对多模型、多对多模型)

一.模型迁移与反向迁移

1.Model --> DB (模型 to 数据库)

(1)迁移步骤
    生成迁移文件 python manage.py makemigrations
    执行迁移文件 python manage.py migrate
(2)迁移文件的生成
    根据models文件生成对应的迁移文件
    根据models和已有迁移文件差别 生成新的迁移文件
(3)迁移原理 了解
     先去迁移记录查找,哪些文件未迁移过
       app_label + 迁移文件名字
       执行未迁移的文件
       执行完毕,记录执行过的迁移文件
(4)可以指定迁移的app
       python manage.py makemigrations app(注意app的名字后面不允许加/)
       python manage.py migrate

(5)注意:
对已经迁移过的模型添加字段时没有给默认值,再次迁移会报错:
在这里插入图片描述

django所有被迁移的字段,都是not null 的约束,不允许为null
添加新的字段的时候,必须指定默认值。
在这里插入图片描述

(6)重新迁移
    删除迁移文件
       migrations所涉及的迁移文件
    删除迁移文件产生的表
    删除迁移记录
       django-migrations

2.DB --> Model (数据库 to 模型)

DB -> Model
   反向生成到指定得app下 --》 python manager.py inspectdb > App/models.py
   元信息中包含一个属性 managed=False 不支持迁移
   如果自己的模型不想被迁移系统管理,也可以使用 managed=False进行声明
创建一个动物表:
在这里插入图片描述
输入:python manager.py inspectdb > App/models.py
在这里插入图片描述
在从服务器下载下来:
在这里插入图片描述
你就会发现有了animal表,不好的地方就是会把那13张默认的表也导下来。。。
在这里插入图片描述

如果在元信息中添加了managed = False,那么就代表该模型不受迁移管理

二.模型关系

1.一对一

(1)应用场景

用于复杂表的拆分
扩展新功能
OneToOneField
确认主从关系,谁声明关系谁就是从表
底层实现,使用外键实现的,对外键添加了唯一约束

创建一对一模型:

class Student(models.Model):
    name = models.CharField(max_length=32)

    class Meta:
        db_table = 'student'


class IdCard(models.Model):
    cardnum = models.IntegerField()
    i_student = models.OneToOneField(Student)

    class Meta:
        db_table = 'idcard'

idcard的DDL展示:
在这里插入图片描述

(2)添加

1.添加主表数据
创建根路由:

url(r'^one/',include('OneToOneApp.urls'))

创建子路由:

url(r'^addStudent/',views.addStudent),

生成视图函数:

def addStudent(request):
    student = Student()
    student.name = '源'

    student.save()
    return HttpResponse('添加成功')

运行结果:
在这里插入图片描述
2.添加从表数据

创建子路由:

url(r'^addIdcard/',views.addIdcard),

生成视图函数:
按照添加主表数据的操作,我们可以试着写下添加从表数据:

def addIdcard(request):
    idcard = IdCard()
    idcard.cardnum = '110'

    idcard.save()
    return HttpResponse('添加成功')

运行结果:
在这里插入图片描述
通过结果,我们会发现会报错。实际上,在默认情况下,django所有的字段都是not null的,非空的,如果想设置字段为nulll,那么可以添加索引:

class IdCard(models.Model):
    cardnum = models.IntegerField()
    i_student = models.OneToOneField(Student,null=True,blank=True)

    class Meta:
        db_table = 'idcard'

执行迁移,再运行:
在这里插入图片描述

添加从表数据,注意外键的null值
修改了模型之后,null和blank都必须要迁移,否则不能生效

3.绑定
创建子路由:

url(r'^bind/',views.bind),

生成视图函数:

def bind(request):
    student = Student.objects.last()
    idcard = IdCard.objects.last()

    # 针对于模型
    idcard.i_student = student
    # 针对于表
    # idcard.i_student_id = student.id 也可以

    idcard.save()

    return HttpResponse('绑定成功')

运行结果:
在这里插入图片描述
思考
以现在的数据基础上 一个student 一个idcard
(1)以现在的数据基础上,再次添加student对象,然后进行绑定,可不可以?(可以)
在这里插入图片描述

(2)以现在的数据基础上,再次添加idcard对象,然后进行绑定,可不可以?(不可以)

在这里插入图片描述

(3)删除

1.删除从表数据
创建子路由:

url(r'^deleteIdcard',views.deleteIdcard)

生成视图函数:

def deleteIdcard(request):
    idcard = IdCard.objects.last()
    idcard.delete()
    return HttpResponse('删除从表成功')

运行结果:
在这里插入图片描述
2.删除主表数据
(1)删除主表数据,默认的情况是什么???
创建子路由:

url(r'^deleteDefault/',views.deleteDefault)

生成视图函数:

def deleteDefault(request):
    s = Student.objects.last()
    s.delete()

    return HttpResponse('删除主表数据,默认的情况是什么')

运行结果:
在这里插入图片描述

默认情况下,OneToOneField中有一个属性叫做on_delete,该值如果没有,那么默认就是CASCADE,这个代表的是级联,删除主表数据,从表对应的数据将删除

class IdCard(models.Model):
    cardnum = models.IntegerField()
    i_student = models.OneToOneField(Student,on_delete=models.CASCADE)

    class Meta:
        db_table = 'idcard'

(2)删除主表数据,然后对应的从表数据的外键设置为null

class IdCard(models.Model):
    cardnum = models.IntegerField()
   #在设置on_delete=models.SET_NULL的时候,必须在之前指定该字段必须为null
    i_student = models.OneToOneField(Student,null=True,blank=True,on_delete=models.SET_NULL)

    class Meta:
        db_table = 'idcard'

新添数据:
在这里插入图片描述

创建子路由:

url(r'^deleteNull/',views.deleteNull),

生成视图函数:

def deleteNull(request):
    s = Student.objects.last()
    s.delete()
    return HttpResponse('删除主表数据,从表设置为null')

运行结果:
在这里插入图片描述
(3)删除主表数据,然后对应的从表数据的外键设置默认值

class IdCard(models.Model):
    cardnum = models.IntegerField()
   
    i_student = models.OneToOneField(Student,null=True,blank=True,on_delete=models.SET(5))

    class Meta:
        db_table = 'idcard'

添加数据:
在这里插入图片描述
创建子路由:

url(r'^deleteSet/',views.deleteSet),

生成视图函数:

def deleteSet(request):
    s = Student.objects.first()
    s.delete()
    return HttpResponse('删除主表数据,从表数据设置默认值')

运行结果:
在这里插入图片描述
(4)删除主表数据,然后对应的从表有关联数据则不可以删除

class IdCard(models.Model):
    cardnum = models.IntegerField()
    #如果主表下有对应的从表数据,那么就不允许删除,没有对应的数据,才可以删除
    i_student = models.OneToOneField(Student, null=True, blank=True, on_delete=models.PROTECT)

    class Meta:
        db_table = 'idcard'

创建子路由:

url(r'^deleteProtect/',views.deleteProtect),

生成视图函数:

def deleteProtect(request):
    s = Student.objects.last()
    s.delete()

    return HttpResponse('有关联数据,则不允许删除')

运行结果:
在这里插入图片描述
如果将i_student_id设置为null:
在这里插入图片描述

models.PROTECT:使从表数据受保护的
当存在级联数据的时候,删除主表数据,会抛出异常
主表不存在级联数据的时候,可以删除
开发中为了防止误操作,我们通常会设置为此模式

(4)查询

1.根据从表的对象查询主表的数据
创建子路由:

url(r'^getStudent/',views.getStudent),

生成视图函数:

def getStudent(request):
    idcard = IdCard.objects.last()
    # i_student是idcard的显性属性,显性函数就是可以直接看到的属性
    print(idcard.i_student.name)

    return HttpResponse('根据从表对象来查询主表对象')

运行结果:
在这里插入图片描述
2.根据主表的对象,来查询从表的数据
创建子路由:

url(r'^getIdcard/',views.getIdcard),

生成视图函数:

def getIdcard(request):
    student = Student.objects.last()
    # 当主表对象查询从表数据的时候可以使用隐性属性
    #    隐性属性:看不到 但是可以使用
    #    1v1: student.idcard
    #    1vm:  stdent.idcard_set
    print(student.idcard.cardnum)
    return HttpResponse('根据主表对象来查询从表数据')

运行结果:
在这里插入图片描述

2.一对多

(1)创建模型

创建一对多模型,并进行迁移

class Dept(models.Model):
    name = models.CharField(max_length=32)

    class Meta:
        db_table = 'dept'

class Emp(models.Model):
    name = models.CharField(max_length=32)

    e_dept = models.ForeignKey(Dept)

    class Meta:
        db_table = 'emp'

(2)添加

创建主路由:

url(r'^onetomany/',include('OneToMany.urls')),

1.添加主表数据
创建子路由:

url(r'^addDept/',views.addDept),

生成视图函数:

def addDept(request):
    dept = Dept()
    dept.name = 'python开发部'
    dept.save()
    return HttpResponse('添加主表成功')

运行结果:
在这里插入图片描述
2.添加从表数据
创建子路由:

url(r'^addEmp/',views.addEmp),

生成视图函数:

def addEmp(request):
    emp = Emp()
    emp.name = '张三'
    emp.save()

    return HttpResponse('添加从表成功')

运行结果:
在这里插入图片描述

由上可知:一对多的外键也不能为null

重新修改模型:

class Emp(models.Model):
    name = models.CharField(max_length=32)
    
    e_dept = models.ForeignKey(Dept,null=True,blank=True)

    class Meta:
        db_table = 'emp'

再次运行:
在这里插入图片描述

(3)绑定

创建子路由:

url(r'^bind/',views.bind),

生成视图函数:

def bind(request):
    dept = Dept.objects.last()
    emp = Emp.objects.last()

    emp.e_dept = dept
    emp.save()

    return HttpResponse('绑定成功')

运行结果:
在这里插入图片描述
思考
(1) 以现在已有数据的基础之上,如果在主表中添加一个数据,然后绑定,可以不可以?

在主表中添加一个数据:
在这里插入图片描述
在这里插入图片描述

再进行绑定,运行结果:
在这里插入图片描述

以现在已有数据的基础之上,如果在主表中添加一个数据,然后绑定  -->可以

(2) 以现在已有数据的基础之上,如果在从表中添加一个数据,然后绑定,可以不可以?

在从表中添加一个数据:
在这里插入图片描述
在这里插入图片描述
再进行绑定,运行结果:
在这里插入图片描述

以现在已有数据的基础之上,如果在从表中添加一个数据,然后绑定 -->可以

(4)删除

1.删除从表数据
创建子路由:

url(r'^deleteEmp/',views.deleteEmp),

生成视图函数:

def deleteEmp(request):
    emp = Emp.objects.last()
    emp.delete()
    return HttpResponse('删除从表成功')

运行结果:
在这里插入图片描述
2.删除主表数据
(1)默认情况下,是级联删除CASCADE
创建子路由:

url(r'^deleteDefault/',views.deleteDefault),

生成视图函数:

def deleteDefault(request):
    dept = Dept.objects.last()
    dept.delete()
    return HttpResponse('默认删除主表')

运行结果:
在这里插入图片描述
(2)删除主表,从表设置为null
重新修改模型:

class Emp(models.Model):
    name = models.CharField(max_length=32)

    e_dept = models.ForeignKey(Dept, null=True, blank=True, on_delete=models.SET_NULL)
    class Meta:
        db_table = 'emp'

添加数据:
在这里插入图片描述

创建子路由:

url(r'^deleteNull/',views.deleteNull),

生成视图函数:

def deleteNull(request):
    dept = Dept.objects.last()
    dept.delete()

    return HttpResponse('删除主表,从表数据设置为null')

运行结果:
在这里插入图片描述

(3)删除主表,如果有关联从表数据,就报错,不允许删除
重新修改模型:

class Emp(models.Model):
    name = models.CharField(max_length=32)

    e_dept = models.ForeignKey(Dept, null=True, blank=True, on_delete=models.PROTECT)

    class Meta:
        db_table = 'emp'

添加数据:
在这里插入图片描述
创建子路由:

url(r'^deleteProtect/',views.deleteProtect),

生成视图函数:

def deleteProtect(request):
    dept = Dept.objects.last()
    dept.delete()
    return HttpResponse('删除主表,有从表的对应数据,则报错')

运行结果:
在这里插入图片描述

删除:数据删除同一对一模型一样
删除主表数据:默认级联从表数据
修改on_delete属性为models.PROTECT
  有级联数据数据 抛异常
  没有级联数据 可以正常删除
修改on_delete=models.SET_NULL
   有级联数据 外键值设置为null
  没有级联数据 直接删除
删除字表数据 不管字表返回得是列表还是单个数据 都可以直接删除 应用场景 多选删除

(5)查询

1.根据从表对象查询主表数据
创建子路由:

url(r'^getDept/',views.getDept),

生成视图函数:

def getDept(request):
    emp = Emp.objects.get(pk=3)
    print(emp.e_dept.name)
    return HttpResponse('根据从表的数据查询主表的数据')

运行结果:
在这里插入图片描述

2.根据主表对象查询从表数据
创建子路由:

url(r'^getEmps/',views.getEmps),

生成视图函数:

def getEmps(request):
    dept = Dept.objects.last()
    emps = dept.emp_set.all()

    for e in emps:
        print(e.id,e.name)
    return HttpResponse('根据主表对象查询从表的数据')

运行结果:
在这里插入图片描述

查询:级联对象获取
从获取主
   显性属性
主获取从
   隐性属性
   默认是 模型小写_set
     该属性得返回值类型是relatedManager类型
      注意relatedManager是一个不可以迭代得对象 所以需要调用Manager得方法
    relatedManager也是Manager的一个子类
      relatedManager对象可以调用filter、exclude、all、切片

3.多对多

(1)创建模型

创建多对多模型,并进行迁移:

class Custom(models.Model):
    name = models.CharField(max_length=32)

    class Meta:
        db_table = 'custom'

class Goods(models.Model):
    name = models.CharField(max_length=32)

    g_custom = models.ManyToManyField(Custom)

    class Meta:
        db_table = 'goods'

Django自动生成关系表:

ManyToManyField
产生表的时候会产生单独的关系表
关系表中存储关联表的主键,通过多个外键实现的,多个外键联合唯一
会产生额外的关系表
  表中使用多个外键实现
  外键对应关系表的主键

(2)添加

创建主路由:

url(r'^manytomany/',include('ManyToManyApp.urls')),

1.添加主表数据
创建子路由:

url(r'^addCustom/',views.addCustom),

生成视图函数:

def addCustom(request):
    custom = Custom()
    custom.name = '张三'
    custom.save()
    return HttpResponse('添加主表数据')

运行结果:
在这里插入图片描述
2.添加从表数据
创建子路由:

url(r'^addGoods/',views.addGoods),

生成视图函数:

def addGoods(request):
    goods = Goods()
    goods.name = '手办'
    goods.save()
    return HttpResponse('添加从表数据')

运行结果:
在这里插入图片描述
3.添加关系表数据
创建子路由:

url(r'^addRelation/',views.addRelation),

生成视图函数:
方式一:

def addRelation(request):
    custom = Custom.objects.last()
    goods = Goods.objects.last()

    #从表的显性属性,来添加关系表的数据
    goods.g_custom.add(custom)
    
    return HttpResponse('添加关系表数据')

方式二:

def addRelation(request):
    custom = Custom.objects.last()
    goods = Goods.objects.last()

    # 主表的隐性属性,来添加关系表的数据
    custom.goods_set.add(goods)
    
    return HttpResponse('添加关系表数据')

运行结果:
在这里插入图片描述

需要注意的是:关系表中外键的联合唯一

(3)删除

1.删除主表数据
创建子路由:

url(r'^deleteCustom/',views.deleteCustom),

生成视图函数:

def deleteCustom(request):
    custom = Custom.objects.last()
    custom.delete()
    return HttpResponse('删除custom是不是级联删除???')

运行结果:
在这里插入图片描述

删除主表数据,默认是级联删除

2.删除从表数据
数据展示:
在这里插入图片描述
创建子路由:

url(r'^deleteGoods/',views.deleteGoods),

生成视图函数:

def deleteGoods(request):
    goods = Goods.objects.first()
    goods.delete()
    return HttpResponse('删除goods是不是级联删除???')

运行结果:
在这里插入图片描述

删除从表数据,也是级联删除

3.删除关系表数据
数据展示:
在这里插入图片描述
创建子路由:

url(r'^deleteRelation/',views.deleteRelation),

生成视图函数:
方式一:

def deleteRelation(request):
    custom = Custom.objects.first()
    goods = Goods.objects.first()
    # 根据从表的显性属性 删除
    goods.g_custom.remove(custom)

    return HttpResponse('删除关系表数据')

方式二:

def deleteRelation(request):
    custom = Custom.objects.first()
    goods = Goods.objects.first()
    # 根据主表的隐性属性 删除
    custom.goods_set.remove(goods)

    return HttpResponse('删除关系表数据')

运行结果:
在这里插入图片描述

(4)查询

1.根据从表数据查询主表数据
创建子路由:

url(r'^getCustom/',views.getCustom),

生成视图函数:

def getCustom(request):
    goods = Goods.objects.first()
    customs = goods.g_custom.all()

    for custom in customs:
        print(custom.id,custom.name)

    return HttpResponse('根据从表的数据查询主表的数据')

运行结果:
在这里插入图片描述

2.根据主表数据查询从表数据
创建子路由:

url(r'^getGoods/',views.getGoods),

生成视图函数:

def getGoods(request):
    custom = Custom.objects.first()
    goods_list = custom.goods_set.all()
    
    for goods in goods_list:
        print(goods.id,goods.name)
        
    return HttpResponse('根据主表的数据查询从表的数据')

运行结果:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Django模型中实现购物车功能,需要建立两个模型:一个是购物车模型,用于存储用户的购物车信息;另一个是购物车商品模型,用于存储用户购物车中的商品信息。 以下是购物车模型和购物车商品模型的代码示例: ```python from django.db import models from django.contrib.auth.models import User class ShoppingCart(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) # 其他购物车相关字段 class ShoppingCartItem(models.Model): cart = models.ForeignKey(ShoppingCart, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE) quantity = models.IntegerField(default=1) # 其他购物车商品相关字段 ``` 在上面的代码中,`ShoppingCart` 模型与 `User` 模型建立了一对一关系,用于存储用户的购物车信息,`ShoppingCartItem` 模型与 `ShoppingCart` 模型建立了一对多关系,用于存储购物车中的商品信息,其中 `product` 字段是一个外键,关联到商品模型。 在视图中,可以通过以下方式向购物车中添加商品: ```python from django.shortcuts import get_object_or_404 from .models import ShoppingCart, ShoppingCartItem from products.models import Product def add_to_cart(request, product_id): # 获取当前用户的购物车 cart, created = ShoppingCart.objects.get_or_create(user=request.user) # 获取要添加到购物车中的商品 product = get_object_or_404(Product, id=product_id) # 将商品添加到购物车中 item, created = ShoppingCartItem.objects.get_or_create(cart=cart, product=product) if not created: item.quantity += 1 item.save() # 返回购物车页面 return redirect('cart') ``` 在上面的代码中,首先获取当前用户的购物车,然后获取要添加到购物车中的商品。接着,通过 `ShoppingCartItem.objects.get_or_create()` 方法向购物车中添加商品,如果商品已经存在于购物车中,则将商品数量加 1。 这样就可以实现在 Django 中购物车添加多个商品了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值