简体   繁体   English

如何将不同的 Db 模型合并为一个?

[英]How can I merge different Db Models into one?

I have an old Django Project, which I started when I was a beginner.我有一个旧的 Django 项目,我是初学者时就开始的。 So far it worked but, due to some code refactoring I would like to do, I would like to change the original database models.到目前为止它有效,但是由于我想进行一些代码重构,我想更改原始数据库模型。 Basically, I originally made many different models, each one for a user type.基本上,我最初做了很多不同的模型,每一个都针对一种用户类型。

old models:旧型号:

class CustomUser(AbstractUser):
    user_type_data = (
        ('admin', 'Admin'),
        ('instructor', 'Instructor'),
        ('student', 'Student'),
        ('renter', 'Renter'),
    )
    user_type = models.CharField(
        max_length=20, choices=user_type_data, default=1)


class Admin(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    date_of_birth = models.DateField(null=True, blank=True)
    fiscal_code = models.CharField(max_length=50, null=True, blank=True)
    phone = models.CharField(max_length=50, null=True, blank=True)
    picture = models.ImageField(
        blank=True, null=True, default='default.png')
    address = models.CharField(max_length=100, blank=True, null=True)
    cap = models.CharField(max_length=10, blank=True, null=True)
    city = models.CharField(max_length=100, blank=True, null=True)
    province = models.CharField(
        max_length=100, choices=PROVINCE_CHOICES, blank=True, null=True)
    country = CountryField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.user.username

    class Meta:
        ordering = ['last_name']


class Instructor(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    date_of_birth = models.DateField(null=True, blank=True)
    fiscal_code = models.CharField(max_length=50,  null=True, blank=True)
    phone = models.CharField(max_length=50,  null=True, blank=True)
    picture = models.ImageField(
        blank=True, null=True, default='default.png')
    address = models.CharField(max_length=100, null=True, blank=True)
    cap = models.CharField(max_length=10, null=True, blank=True)
    city = models.CharField(max_length=100, null=True, blank=True)
    province = models.CharField(
        max_length=100, choices=PROVINCE_CHOICES, blank=True, null=True)
    country = CountryField(blank=True, null=True)
    is_active = models.BooleanField(default=True)
    flight_wage = models.FloatField(null=True, blank=True)
    theory_wage = models.FloatField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.last_name + ' ' + self.user.first_name

    class Meta:
        ordering = ['last_name']

I posted just the first two user type but you get the picture.我只发布了前两种用户类型,但你明白了。 A lot of redundant code.大量冗余代码。 What I would like to achieve is something like that:我想要实现的是这样的:

new models.py:新模型.py:

class CustomUser(AbstractUser):

    user_type_data = (
        ('admin', 'Admin'),
        ('instructor', 'Instructor'),
        ('student', 'Student'),
        ('renter', 'Renter'),
    )
    user_type = models.CharField(
        max_length=20, choices=user_type_data, default=1)
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    date_of_birth = models.DateField(null=True, blank=True)
    fiscal_code = models.CharField(max_length=50,  null=True, blank=True)
    phone = models.CharField(max_length=50,  null=True, blank=True)
    picture = models.ImageField(
        blank=True, null=True, default='default.png')
    address = models.CharField(max_length=100, null=True, blank=True)
    cap = models.CharField(max_length=10, null=True, blank=True)
    city = models.CharField(max_length=100, null=True, blank=True)
    province = models.CharField(
        max_length=100, choices=PROVINCE_CHOICES, blank=True, null=True)
    country = CountryField(blank=True, null=True)
    is_active = models.BooleanField(default=True)
    flight_wage = models.FloatField(null=True, blank=True)
    theory_wage = models.FloatField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.last_name + ' ' + self.user.first_name

    class Meta:
        ordering = ['last_name']

My question is: Is it possibile to adapt my old projects (I already have two customers using the old project) to this new brand type of database model?我的问题是:是否可以将我的旧项目(我已经有两个客户在使用旧项目)适应这个新品牌类型的数据库 model?

I would do this with the following steps:我将通过以下步骤执行此操作:

  1. Add new fields to existing user model, make sure to add null=True for all new fields向现有用户 model 添加新字段,确保为所有新字段添加 null=True
  2. Create migrations file for the user model为用户 model 创建迁移文件
  3. Inside the migrations file add a migrations.RunPython command to add the values from the Admin model to each corresponding user.在迁移文件中添加一个 migrations.RunPython 命令以将 Admin model 中的值添加到每个相应的用户。
  4. Run Migration and remove null=True from all fields where not necessary运行迁移并从所有不需要的字段中删除 null=True
  5. Refactor all code to refer to user model instead of admin model重构所有代码以引用用户 model 而不是管理员 model
  6. Remove admin model删除管理员 model

The same can be done for the Instructor model可以对 Instructor model 执行相同的操作

I'll give an example for step 3 here:我将在这里给出第 3 步的示例:

## Example migration file

from django.db import migrations

def add_values_to_user(apps, schema):
    CustomUser = apps.get_model('users', 'CustomUser')

    for user in CustomUser.objects.all():
        if user.admin:
            user.first_name = user.admin.first_name
        elif user.instructor:
            user.first_name = user.instructor.first_name
        # Do this for all values you require for the admin and instructor model

        user.save()

class Migration(migrations.Migration):

    dependencies = [
        ('users', '0046_auto_20220506_1523'),
    ]

    operations = [
        migrations.RunPython(add_values_to_user)
    ]



Maybe what you are looking for are Proxy models: https://docs.djangoproject.com/en/4.1/topics/db/models/#proxy-models也许你正在寻找的是代理模型: https://docs.djangoproject.com/en/4.1/topics/db/models/#proxy-models

From docs: This is what proxy model inheritance is for: creating a proxy for the original model. You can create, delete and update instances of the proxy model and all the data will be saved as if you were using the original (non-proxied) model. The difference is that you can change things like the default model ordering or the default manager in the proxy, without having to alter the original.来自文档: This is what proxy model inheritance is for: creating a proxy for the original model. You can create, delete and update instances of the proxy model and all the data will be saved as if you were using the original (non-proxied) model. The difference is that you can change things like the default model ordering or the default manager in the proxy, without having to alter the original.

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

The MyPerson class operates on the same database table as its parent Person class. In particular, any new instances of Person will also be accessible through MyPerson, and vice-versa

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM