外键中的许多型号 [英] Many models in Foreign Key

查看:69
本文介绍了外键中的许多型号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个模型,员工

员工


  • 名称: CharField

  • 电子邮件: EmailField

  • 类型: ForeignKey

  • Name: CharField
  • Email: EmailField
  • Type: ForeignKey

问题出在 type 字段。我希望外键能够几种不同类型的模型。例如,一个用于 Software Developer ,另一个用于 Janitor ,依此类推。

The problem is with the type field. I want the foreign key to be able to be several different types of models. For example, one for Software Developer, another for Janitor, and so on.

我可以通过为所有类型设置一个外键字段并将其中许多设置为null来做到这一点,但这似乎很糟糕。

如何实现?谢谢!!!!

How can I achieve this? Thanks!!

推荐答案

有很多方法可以将这种多态水平建模到这样的场景中。

There are many ways you can model this level of polymorphism into a scenario like this.

选项1-混凝土基础模型

OPTION 1 - Concrete Base Model

包括 employee_type 字段,指示正在使用的具体模型。

Including a employee_type field which indicates the concrete model being used.

class Employee(models.Model):
    name = models.CharField(max_length=50)
    email = models.CharField(max_length=80)
    employee_type = models.CharField(max_length=20)

class Janitor(Employee):
    [...]

class SoftwareEngineer(Employee):
    [...]

所有共同属性都可以存储在 Employee 模型中。

All mutual attributes can be stored in the Employee model.

一次具体类(软件工程师,Janitor等)被实例化,它将继承其父类的所有属性。

Once a concrete class (Software Engineer, Janitor etc.) is instantiated it will inherit all attributes from it's parent class.

设置并使用 employee_type 您可以区分下注

Setting and using the employee_type you can differentiate between which concrete class was created.

有关此内容的更多信息,请参见此处

More information on this can be found here

[更新]

使用Django 信号可以派生具体的类名称,并将其与关联的实例一起存储。

Using a django Signal the concrete class name can be derived and stored with the associated instance.

signals.py

from django.db.models.signals import pre_save

def store_classname(sender, instance, **kwargs):
    instance.employee_type = instance.__class__.__name__

for subclass in Employee.__subclasses__():
    pre_save.connect(store_classname, sender=subclass)

这可确保每次都存储正确的标识符。

This ensures the correct identifier is stored every time.

现在在您的视图中要选择具体类的类型使用过,您可以在以下情况下继续使用它:

Now in your view where you want to select the type of concrete class to be used, you can either continue using it in a condition like so:

views.py

#EXAMPLE USAGE
employee = Employee.objects.get(id=1)
if employee.employee_type == 'Janitor':
    employee = Janitor.objects.get(id=employee.id)

或通过使用模型名称和对全局变量的查找来动态派生它。

Or derive it dynamically by using the model name and a lookup to global variables.

#EXAMPLE USAGE
from <you_app>.models import *
def get_class(classname):
    cls = globals()[classname]
    return cls

employee = Employee.objects.get(id=1)
concrete_employee = get_class(employee.employee_type)
[...]

注意:更改父模型或子模型的名称时要小心,因为这会影响使用旧模型名称的历史记录。要解决此问题,请使用django的 update() bulk_update 函数将所有旧名称转换为新名称。有关更多信息,请此处

Note: Be careful when changing names of parent or child models as this will affect historical records using the old model name. To fix this use django's update() or bulk_update function to convert all old names to new names. More info is here

选项2- django-polymorphic

OPTION 2 - django-polymorphic

使用名为的django软件包django-polymorphic ,这允许在查询父类时返回所有具体的类。

Using a django package called django-polymorphic, this allows all concrete classes to be returned when parent class is queried on.

models.py

from polymorphic.models import PolymorphicModel

class Employee(PolymorphicModel):
    EMPLOYEE_TYPE_CHOICES = (
        ('Janitor', 'Janitor'),
        ('Software Engineer', 'Software Engineer'),
    )
    name = models.CharField(max_length=50)
    email = models.CharField(max_length=80)

class Janitor(Employee):
    [...]

class SoftwareEngineer(Employee):
    predominant_programming_language= models.CharField(max_length=100)
    [...]

在<$ c $上查询时c>员工会返回以下模型

>>> Employee.objects.filter(id=1)
[ <Employee:         id 1, name "Joe Bloggs", email "example@example.com">,
  <SoftwareEngineer:  id 1, name "Joe Bloggs", email "example@example.com", predominant_programming_language "Python">,]

这篇关于外键中的许多型号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆