Code前端首页关于Code前端联系我们

Django开发:如何在ORM管理视图中自动更新模型字段选择值

terry 2年前 (2023-09-24) 阅读数 83 #后端开发

有两个表,一个是记录网站信息的站点表,结构如下:

CREATE TABLE `site` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `url` varchar(128) NOT NULL,
  `mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  UNIQUE KEY `url` (`url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置网站表'

另一个是用户表记录user信息,结构如下:

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `site_id` bigint(20) unsigned NOT NULL COMMENT 'site.id',
  `user_id` varchar(32) NOT NULL,
  `name` varchar(128) NOT NULL,
  `description` text NOT NULL,
  `mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_id` (`user_id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置用户表'

如上表结构所示,user表中site_id列(简写为user.site_id)的值实际上仅限于id字段的值(缩写为 site.id)在站点表中,实现此目的的错误一种方法是在 user.site_id 和 user.id 两列上指定外键约束。但是,如果由于某种原因无法指定外键约束,则可以跳过用户。 site_id 上的可选字段限制了用户values.site_id 的范围。模型中的代码如下:

# coding=utf-8                                                                                                                                               

from __future__ import unicode_literals

from django.db import models

class Site(models.Model):
    id = models.PositiveIntegerField(primary_key=True, blank=True)
    name = models.CharField(max_length=32, verbose_name=u'网站名称')
    url = models.CharField(max_length=255, verbose_name=u'网址')
    mtime = models.DateTimeField(auto_now=True, verbose_name=u'修改时间')
    ctime = models.DateTimeField(auto_now=True,  verbose_name=u'创建时间')

    class Meta:
        db_table = 'site'


def get_site_choices():
    rcs = Site.objects.all()
    choices = [(x.id, x.name) for x in rcs]
    return choices

class User(models.Model):
    id = models.PositiveIntegerField(primary_key=True, blank=True, verbose_name=u'自增id(留空自动生成)')
    site_id = models.PositiveIntegerField(verbose_name=u'网站', choices=get_site_choices())
    user_id = models.CharField(max_length=32, verbose_name=u'用户id')
    name = models.CharField(max_length=128, verbose_name=u'用户名')
    description = models.TextField(verbose_name=u'备注')
    mtime = models.DateTimeField(auto_now=True, verbose_name=u'修改时间')
    ctime = models.DateTimeField(auto_now=True,  verbose_name=u'创建时间')

    class Meta:
        db_table = 'user'

在Django后端创建两个ORM管理视图。考虑站点表中已经录入了以下两条数据:

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

那么对用户表进行ADD USER操作时,site_id的可选值为豆瓣电影和豆瓣阅读

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

添加了豆瓣读书的用户账号后,用户表如下:

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

现在看起来一切正常,但是如果你在站点表中添加一个网站,比如豆瓣音乐,那么站点表就会更新为三个记录:豆瓣读书、豆瓣电影、豆瓣音乐。但是,如果你想在记录当前用户表中再添加一个,site_id下拉列表中仍然只有两个值:豆瓣读书和豆瓣电影:

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

这是因为site_id = models .PositiveIntegerField(verbose_name=u'website ', Choices=get_site_choices() in class User)) 该语句只会在服务启动时类初始化时执行一次。此时会执行get_site_choices函数,此时的site.id值会作为user.site_id选项被移除,并在site表中添加一个新的值。或者减少记录后,由于User类中的初始化语句将不再被执行,因此会出现两个值不一致的问题。在这种情况下,如果您想更新 user.site_id 值,只需重新启动服务即可。 。

但是,每次更新站点表都必须重新启动服务,这是绝对不能接受的。解决方案是每次在类的 __init__ 方法中重新查询 site 表中的正确值,然后重新从 user.site_id 字段中将值分配给可选字段。获取user.site_id字段是通过self.get_field函数实现的。代码如下:

class User(models.Model):
    id = models.PositiveIntegerField(primary_key=True, blank=True, verbose_name=u'自增id(留空自动生成)')
    site_id = models.PositiveIntegerField(verbose_name=u'网站', choices=get_site_choices())
    user_id = models.CharField(max_length=32, verbose_name=u'用户id')
    name = models.CharField(max_length=128, verbose_name=u'用户名')
    description = models.TextField(verbose_name=u'备注')
    mtime = models.DateTimeField(auto_now=True, verbose_name=u'修改时间')
    ctime = models.DateTimeField(auto_now=True,  verbose_name=u'创建时间')
                                                                                                                                                             
    def __init__(self, *args, **kargs):
        super(User, self).__init__(*args, **kargs)
        self._meta.get_field('site_id').choices = get_site_choices()

    class Meta:
        db_table = 'user'

get_field函数的说明请参见Django文档(https://docs.djangoproject.com/en/2.0/ref/models/meta/#django.db.models.options) .Options. get_field):

Options.get_field(field_name)[源]列更改名称名称给定field_ name 可以是模型中的列名称、抽象模型或继承中的列,或引用该模型的其他模型中定义的字段。在最后一种情况下, Field_name 将是 Related_name 由用户定义或 django 它集写入的名称 ❀❀♽ 不下注带有名称的 Field 。

如果找不到给定名称的列,将引发 FieldDoesNotExist 异常。

这样,在启动每个用户实例时将检索最新的 site.id 字段值。 ,分配给 user.site_id 的可选属性。这样做的缺点是每次初始化都会调用 get_site_choice 。s 并重新分配 user.site_id.choices。如果页面加载的事件较多或者站点表记录较多,就会出现性能问题,所以只适合后台数据量较小的情况,自动更新ADD USER上的最新选择页面无需重新启动服务:

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

Django开发:实现 ORM admin view中model字段choices取值自动更新的一种方法

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门