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

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)的取值其实仅限于site表中的id字段(简写为site.id)的取值,一种实现方式是在user.site_id和user.id两个字段上定义外键约束,但是如果由于某些原因,不能定义外键约束的话,可以通过在Django后台的model代码中,通过user.site_id的choices字段限制user.site_id的可取值范围,model中的代码如下所示:

# 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的admin view,假设site表中已经插入了以下两条数据:

那么在user表中执行ADD USER操作时,site_id的可选值就是豆瓣电影和豆瓣读书两个了

增加一个属于豆瓣读书旗下的用户帐号后user表如下:

目前看来一切正常,但是如果在site表里面增加一个网站,比如豆瓣音乐后,site表里面会更新为豆瓣读书、豆瓣电影、豆瓣音乐三条记录,然而这时要是想在user表中再添加一条记录,site_id的下拉列表中却依然只有豆瓣读书、豆瓣电影两个取值:

这是因为class User中的 site_id = models.PositiveIntegerField(verbose_name=u'网站', choices=get_site_choices()) 这条语句只会在服务启动时类初始化的时候执行一次,这个时候会执行get_site_choices函数,将当时site.id的取值都拿出来作为user.site_id的choices,而在site表中新增或者减少了记录后,由于User类中的初始化语句并不会重新执行,所以会存在两个取值不一致的的问题,这种情况下要想更新user.site_id的取值,只能重启服务了。

然而每次更新了site表后,都需要重启服务的话那就完全不可接受了,解决方案是在class的__init__方法中,每次重新查询site表中的有效取值,而后重新给user.site_id字段的choices字段赋值,获取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)[source]

Returns the field instance given a name of a field.

field_name can be the name of a field on the model, a field on an abstract or inherited model, or a field defined on another model that points to the model. In the latter case, the field_name will be the related_name defined by the user or the name automatically generated by Django itself.

Hidden fields cannot be retrieved by name.

If a field with the given name is not found a FieldDoesNotExist exception will be raised.

如此在每一个user实例初始化时都会重新获取最新的site.id字段的取值,赋给user.site_id的choices属性,这样的缺点是每个实例初始化都会调用get_site_choices并对user.site_id.choices重新赋值,当一个页面加载的实例很多或者site表记录很多的时候,会存在性能问题,因而仅适合后台数据量较少的情况。

如下为在site表中新插入豆瓣阅读网站后,在不重启服务的情况下,ADD USER页面中自动更新为最新choices的效果:

实现Django ORM admin view中model字段choices取值自动更新的一种方法的更多相关文章

  1. CATransform3D中m34字段的取值含义

    转载自:http://zhidao.baidu.com/link?url=OlVQoGOKIBmaXKgQisOLtzliTLPvreOOsRmny3yebA1Wb6-B3KtuKlRXmv0tO3y ...

  2. asp.net mvc 在View中获取Url参数的值

    如果url是 /home/index?id=3 直接Request就ok. 但是如果路由设定为:{controller}/{action}/{id} url是 /home/index/3   这时想在 ...

  3. asp.net mvc 如何在View中获取Url参数的值

    如果url是 /home/index?id=3 直接Request就ok. 但是如果路由设定为:{controller}/{action}/{id} url是 /home/index/3   这时想在 ...

  4. c#利用反射实现对类中的常量进行取值和对应常量的注释

    C#利用反射实现对类中的常量进行取值和对应常量的注释 项目示例:https://gitee.com/dhclly/IceDog.GenerateErrorCode 因为业务需要,项目中有大量的错误码, ...

  5. 【转】oracle 中随机取一条记录的两种方法

    oracle 中随机取一条记录的两种方法 V_COUNT INT:=0; V_NUM INT :=0; 1:TBL_MYTABLE 表中要有一个值连续且唯一的列FID BEGIN SELECT COU ...

  6. hibernate的dao中参数的传递取值

    hibernate的dao中参数的传递取值 private Query setParameter(Query query, Map<String, Object> map) { if (m ...

  7. (转)在网页中JS函数自动执行常用三种方法

    原文:http://blog.sina.com.cn/s/blog_6f6b4c3c0100nxx8.html 在网页中JS函数自动执行常用三种方法 在网页中JS函数自动执行常用三种方法 在HTML中 ...

  8. Java中取小数点后两位(四种方法)

    摘自http://irobot.iteye.com/blog/285537 Java中取小数点后两位(四种方法)   一 Long是长整型,怎么有小数,是double吧     java.text.D ...

  9. 关于JAVA中Byte类型的取值范围的推论(*零为正数,-128在计算机中的表示方法...)

    先看一段推理<*一切都是在8个比特位的前提下,讨论二进制的符号位,溢出等等,才有意义*> +124:0111 1100 -124:1000 0100 +125:0111 1101 -125 ...

随机推荐

  1. D3——Axes

    使用d3.svg.axis() 创建一个 axis function: var xAxis = d3.svg.axis(); an axis function is called, it doesn’ ...

  2. JavaScript浏览器对象模型(BOM)之window对象

    一.BOM概述 BOM(Browser Object Model)浏览器对象模型,它提供了很多对象,用于访问浏览器的功能. BOM 缺少规范,每个浏览器提供商又按照自己想法去扩展它,那么浏览器共有对象 ...

  3. Maven经常使用命令

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/UP19910522/article/details/25985021 Maven库: http:// ...

  4. BZOJ1972:[SDOI2010]猪国杀(模拟)

    Description 太长就不贴过来了 Solution 这个题是真的不难写……唯一的难度就在于理解题意上面……感觉这就是个阅读理解题啊…… 而且你三国杀玩的越多可能就越难写因为你无法理解那些猪的思 ...

  5. [19/04/23-星期二] GOF23_创建型模式(工厂模式、抽象工厂模式)

    一.工厂模式(分为:简单工厂模式.工厂方法模式.抽象工厂模式) 实现了创建者和调用者的分离 核心本质:1.实例化对象,用工厂方法代替new操作:2.将选择实现类.创建对象统一管理和控制,从而将调用者跟 ...

  6. 2016-2017-20155329 《Java程序设计》第9周学习总结

    学号 2016-2017-20155329 <Java程序设计>第9周学习总结 教材学习内容总结 学习目标 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义 ...

  7. Spring Cloud Consul 之Greenwich版本全攻略

    什么是Consul Consul是HashiCorp公司推出的开源软件,使用GO语言编写,提供了分布式系统的服务注册和发现.配置等功能,这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全 ...

  8. iOS:文字相关(19-01-08更)

    0.写在前面 1.小技巧 UILabel类: 1-1-1).设置行间距富文本,有省略号要求的,需要再次设置省略(初始化时设置的会失效). UITextField类: 1-2-1).清空按钮. UITe ...

  9. 网站jcms流程分析

    本实例大致流程:基于jsp页面,通过servlet传递数据调用方法,利用service更改数据库.本文重点分析的是其中的两个小方法add()和delete(),来反映出反射机制的一个具体作用:减少Se ...

  10. vue中的slot(插槽)

    vue中的插槽----slot 什么是插槽? 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性. ...