【问题标题】:How to create and serialize an unmanaged model Django如何创建和序列化非托管模型 Django
【发布时间】:2021-08-09 14:52:52
【问题描述】:

我目前在我的数据库中有现有的表,这些表是按照通常的方式使用模型创建的(使用 makemigrationsmigrate)。

现在,我希望合并这些现有表中的某些数据,而无需在我的数据库中创建新表。然后,我想对这些数据进行序列化,以便通过视图 API 对其进行访问。

我的理解是我创建了一个非托管模型来处理这个问题。我理解作为文档的一部分,您需要指定 managed = False 但这只是一个开始。到目前为止,我实际上只找到了一个链接(这不是很有帮助):https://riptutorial.com/django/example/4020/a-basic-unmanaged-table-

假设说,我在现有数据库的许多不同表中输入了用户信息,我想在我的新非托管模型中创建某些数据点,以将其组合到一个序列化程序中。到目前为止,这就是我想出的。请注意,在我的用户模型中,我不知道为 db_tables 参数指定什么,因为正如我所提到的,数据将来自许多不同的表,而不仅仅是一个。

用户模型

from django.db import models

class UserModel(models.model):
    user = models.CharField(db_column="LABEL", max_length=255)

    class Meta:
        managed = False
        db_table = "Sample_Table_1"

用户序列化器

from rest_framework import serializers
from models.user import UserModel

class UserSerializer(serializer.ModelSerializer):
    class Meta:
        model = UserModel
        fields = "__all__"

用户视图集

from rest_framewirk.viewsets import ModelViewSet 
from models.user import UserModel 
from serializers.user import UserSerializer

class UserViewSet(ModelViewSet):
    queryset = UserModel.objects.all()
    serializer_class = UserSerializer

    def list(self, request **kwargs):
        return super(UserViewSet, self).list(request)

如果我想从db_table = "Sample_Table_1" 以外的其他表中获取另一个数据点,我该从哪里开始?例如,如果我想要来自 Sample_Table_2 表的数据?

我认为我的主要问题是我真的不知道非托管模型是如何工作的,以及我如何从数据库中已经存在的不同表中检索数据。如果有人可以向我指出可以帮助我的教程,那将是一个好的开始。

【问题讨论】:

  • 您的数据库中已经存在表?参考这个docs.djangoproject.com/en/3.2/howto/legacy-databases
  • 是的,我的数据库中已经存在表。例如,一个包含一堆当前用户信息的用户表。
  • 您的 UserModel 似乎被命名为 UserDetails...?
  • 抱歉,这是一个复制/粘贴错误。我已经更改了一些名称,因为我无法提及我正在使用的真实姓名。
  • @Adam,看起来您只需要常规序列化程序,而不是模型序列化程序,因为您从这些 managed=False 模型中获得的唯一东西是列出您想要序列化的字段,而不是它?定义序列化器,使用 SerializerMethodFields 事情变得棘手,你根本不需要接触模型。

标签: python sql django django-models django-rest-framework


【解决方案1】:

如果您想合并来自不同表的数据,您可以尝试使用 DB 视图。 并在其前面放置一个非托管模型。 例如:

1) 创建一个 managed=False 的模型
class UserModel(models.Model):
    user = models.CharField(db_column="user", max_length=255)

    class Meta:
        managed = False
        db_table = "sample_table_1"
2) 运行 makemigrations

在迁移文件中使用 RunSQL 创建一个 DB 视图(假设为 Postgres)

class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='UserModel',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('user', models.CharField(db_column='user', max_length=255)),
            ],
            options={
                'db_table': 'sample_table_1',
                'managed': False,
            },
        ),
        migrations.RunSQL(
            sql="""
                CREATE OR REPLACE VIEW sample_table_1 AS
                SELECT id, username AS user FROM auth_user;
                # Here I used <username> as an example
                """,
            reverse_sql="""
                DROP VIEW IF EXISTS sample_table_1;
                """
        )
    ]

3) 运行迁移
4) 创建序列化程序
class UserModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserModel
        fields = '__all__'

有用的链接: https://www.fusionbox.com/blog/detail/using-materialized-views-to-implement-efficient-reports-in-django/643/

https://schinckel.net/2020/03/03/postgres-view-from-django-queryset/

【讨论】:

    【解决方案2】:

    如果数据库中已经有表,通常应该使用inspectdb [Django docs] 管理命令来生成这些表的至少基本结构作为模型,您可能需要修复一些 Django 无法正确推断的问题。您将(在正确配置数据库设置后)运行以下命令,这将至少让您开始制作正确的模型:

    python manage.py inspectdb
    

    一般来说,您应该参考文档的Integrating Django with a legacy database 部分。

    进一步,您似乎没有为模型设置正确的表名(因为它已经存在,它的名称可能与 Django 生成的不同),所以如果您想要手动修复,您可以设置模型的Meta 中的db_table [Django docs] 属性:

    class UserDetails(models.model):
        user = models.CharField(db_column="LABEL", max_length=255)
    
        class Meta:
            managed = False
            db_table = '<YOUR_TABLE_NAME_HERE>'
    

    【讨论】:

    • 谢谢你。我还没有查看您提到的文档,但是在这种情况下,db_table 的名称是什么?正如我所提到的,这只是我将要检索的一个字段的一个示例,但本质上,我将组合来自多个表的数据。
    • db_table 将是您在数据库中的表的名称,(正如我的占位符所暗示的那样)。假设在数据库中该表被命名为users,那么您将编写db_table = 'users',或类似名称。虽然我建议使用inspectdb(您可以将表名传递给它以仅在需要时推断特定表,请查看文档)
    • 对不起,我可能误会了什么。虽然 UserDetails 非托管模型中的这个“用户”字段可能会从 users 表中获取数据,但模型本身也会从其他表中聚合数据。这是否意味着我还需要添加所有不同的表?
    • @Adam 我不明白您所说的“模型本身将聚合来自其他表的数据”是什么意思。但是如果你想在你的应用程序中使用这些表,你应该为它们制作模型。
    • 我的意思是非托管模型。我了解创建非托管模型的全部意义在于,当我想从多个不同的表中检索数据然后序列化该数据(使用非托管模型)时,我不必创建新的数据库表。这更有意义吗?
    【解决方案3】:

    如果您想将不同模型的数据返回到单个 api 调用,实现此目的的一种方法是用户 serializers.Serializer

    class TestClass(serializers.Serializer):
        table1 = serializers.IntegerField()
        ......
    

    你可以使用这个类进行序列化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-02
      • 2018-10-14
      • 2014-12-24
      • 2017-10-20
      • 1970-01-01
      • 2013-01-26
      • 1970-01-01
      • 2018-10-29
      相关资源
      最近更新 更多