chan

朝生暮死不足笑 但悲百年不足道

【Django】涉及到外键,为什么存储的是外键对应的实例而非外键对应模型的主键ID呢,明明数据库设计的是存储外键对应模型的主键ID


field_object = models.Issues._meta.get_field(name)
else:
            #条件判断,不是用户输入的值,是自己的值
            instance = field_object.rel.model.objects.filter(id=value,project_id=project_id).first()
            if not instance:
                return JsonResponse({'status': False, 'error': '您选择的值不存在'})
             
            setattr(issues_object,name,instance)

这里涉及到外键,我还是不太理解setattr中使用的instance 

在这段代码中,setattr(issues_object, name, instance) 用来动态地设置 issues_object 对象的属性。让我们逐步分析这段代码的作用,特别是其中涉及到外键的部分。

代码解析

  1. 条件判断和外键查询:python复制代码instance = field_object.rel.model.objects.filter(id=value, project_id=project_id).first() 这行代码的作用是从 field_object(一个表单字段对象)的关联模型中,查找符合条件的记录。假设 field_object 是一个外键字段,field_object.rel.model 就是外键所关联的模型类。
    • filter(id=value, project_id=project_id) 表示从数据库中查找符合 id=valueproject_id=project_id 条件的记录。
    • first() 方法会返回查询结果中的第一条记录,如果没有符合条件的记录,则返回 None
    这里,instance 就是查询到的外键模型实例(例如,某个 Project 模型的实例),或者如果没有找到记录,instanceNone
  2. 如果没有找到外键记录:python复制代码if not instance: return JsonResponse({'status': False, 'error': '您选择的值不存在'}) 如果没有找到符合条件的外键记录,则返回一个错误的 JSON 响应,提示用户选择的值不存在。
  3. 使用 setattr 设置属性:python复制代码setattr(issues_object, name, instance) 这里的 setattr() 函数用于动态地给 issues_object 对象设置一个属性。具体来说:
    • issues_object 是你要操作的对象,假设是一个 Issues 模型实例。
    • name 是你要设置的属性名称,通常是字段名,可能是外键字段的名称(例如 project)。
    • instance 是你从数据库中查找到的外键对象(例如 Project 模型的实例)。
    setattr() 的作用:
    • setattr(issues_object, name, instance) 的作用是将 issues_objectname 属性设置为 instance,即把外键对象(instance)赋值给 issues_object 的外键字段。
    具体来说,假设 nameproject,而 instance 是某个 Project 实例,那么 setattr(issues_object, 'project', instance) 相当于:python复制代码issues_object.project = instance 这就是将 issues_objectproject 字段设置为找到的 Project 实例(instance)。

外键的作用

在 Django 中,外键(ForeignKey)是建立表之间关系的字段,它通常指向另一个模型的实例。外键字段存储的是关联模型的主键值,而实际的数据是存储在关联的模型实例中的。

  • 例如,在 Issues 模型中,可能有一个外键字段 project 指向 Project 模型,表示一个问题(Issues)属于某个项目(Project)。

举例

假设 Issues 模型有一个外键字段 project,指向 Project 模型,模型定义如下:

python复制代码class Project(models.Model):
    name = models.CharField(max_length=100)
    
class Issues(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField()
    project = models.ForeignKey(Project, on_delete=models.CASCADE)

当你在表单中选择了一个项目(Project)时,假设通过表单获取了项目的 id(比如 value),然后通过 filter(id=value, project_id=project_id) 查询数据库,找到对应的 Project 实例(即 instance)。

接下来,setattr(issues_object, 'project', instance) 就是将 Issues 实例 issues_objectproject 字段设置为找到的 Project 实例。

这时,issues_object.project 就变成了 instance,即一个 Project 模型的实例。

总结

  • setattr(issues_object, name, instance) 是动态地给 issues_object 设置属性,其中 name 是属性名,instance 是你查找的外键实例(例如,Project 实例)。
  • 外键字段保存的是关联模型的主键值,但它实际指向的是关联模型的实例。在设置外键字段时,instance 就是关联模型的完整实例对象,而不是只是主键值。

4o

您说:

外键字段存储的是关联模型的主键值,而实际的数据是存储在关联的模型实例中的。所有我比较困惑为什么setattr(issues_object, name, instance)设置的是一个实例呢,不是应该是一个id么。

ChatGPT 说:

ChatGPT

你的疑问非常好,的确需要更详细地理解 Django 外键的工作原理。在 Django 中,外键字段在数据库中存储的是关联对象的 主键值,但当我们操作外键字段时,通常直接使用 关联模型实例。这样做的原因涉及 Django 的 ORM(对象关系映射)机制,它让你可以更方便地操作外键字段,而无需手动处理主键值。

让我们逐步分析:

1. 外键字段在数据库中的存储方式

在数据库中,外键字段是以关联模型的 主键 存储的。举个例子,假设有一个 Issues 模型和一个 Project 模型:

python复制代码class Project(models.Model):
    name = models.CharField(max_length=100)

class Issues(models.Model):
    title = models.CharField(max_length=100)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)

在数据库中,Issues 表会有一个 project_id 字段,它存储的是与 Project 模型的主键关联的值。

假设有一个 Project 实例,其 id 是 1。对于某个 Issues 实例来说,它的 project_id 可能是 1,表示该问题属于 id 为 1 的 Project 实例。

2. 在 Django 中操作外键字段时,使用实例而非主键

在 Django 中,当你设置一个外键字段的值时,你不需要手动处理主键值。Django 会自动处理关联关系,允许你使用关联模型的 实例

例如,你可以通过 Issues 实例的 project 字段直接关联 Project 实例:

python复制代码# 获取一个 Project 实例
project_instance = Project.objects.get(id=1)

# 创建一个 Issues 实例
issue = Issues(title="New Issue", project=project_instance)

# 或者动态设置外键字段
issue.project = project_instance

这里的 project_instanceProject 模型的实例,Django 会自动将它转换为关联的主键值(即 project_id)。你无需手动传递 project.id,Django 会帮你做这件事。

3. setattr 的作用

在你的代码中,setattr(issues_object, name, instance) 动态地设置 issues_objectname 属性为 instance。假设 nameprojectinstance 是某个 Project 实例(例如,project_instance)。通过 setattr 设置后,实际上你做了以下操作:

python复制代码issues_object.project = project_instance

当你执行这行代码时,Django 幕后会做的事情是:

  • project_instance 对象的主键值(project_instance.id)存储到 issues_objectproject 字段中。
  • 在查询时,Django 会把这个主键值映射为 project 字段的 Project 实例。

4. 为什么使用实例而非主键值

使用外键模型实例而不是主键值带来了以下几个好处:

  1. 简化操作:你不需要手动处理外键的主键值,Django 会自动管理这个过程。你可以直接操作关联模型的实例,而无需关心它背后存储的主键值。
  2. 自动处理关联:当你设置一个外键字段时,Django 会自动保存关联的主键值。并且当你通过 issues_object.project 访问该字段时,Django 会自动加载并返回关联的 Project 实例。
  3. 便于关联查询:当你从数据库查询时,Django 会自动通过外键主键值加载关联对象。你可以方便地通过外键字段获取关联模型的数据,而不需要手动拼接 SQL。

5. 总结:为什么使用实例

在 Django 中,外键字段实际上是一个 模型实例,而不是仅仅存储一个主键值。这是因为 Django 的 ORM 设计让你可以更方便地操作外键,简化了数据库交互。外键字段在数据库中存储的是主键值,但你在代码中通常会使用 模型实例 来操作外键,这样 Django 会自动将实例的主键值存储到数据库中,并在需要时加载对应的实例。

当你通过 setattr 设置外键字段时,Django 会自动将实例的主键值存储到数据库的相应外键字段中,这样你就可以像操作普通字段一样操作外键字段,而无需手动管理主键。

评论
还没有评论
    发表评论 说点什么