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

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

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

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

TABLE `user` (
  `id` NULL COMMENT 'site.id'user_id` text KEY `user_id` (`user_id`),1)"> `name` (`name`)
) ENGINE=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  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,1)">网址)
    mtime = models.DateTimeField(auto_now=True,1)">修改时间)
    ctime = models.DateTimeField(auto_now=True,1)">创建时间)

     Meta:
        db_table = site'


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

 User(models.Model):
    id = models.PositiveIntegerField(primary_key=True,blank=True,1)">自增id(留空自动生成))
    site_id = models.PositiveIntegerField(verbose_name=u网站',choices=get_site_choices())
    user_id = models.CharField(max_length=32,1)">用户id)
    name = models.CharField(max_length=128,1)">用户名)
    description = models.TextField(verbose_name=u备注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函数实现的,代码如下:

)
                                                                                                                                                             
    def __init__(self,*args,**kargs):
        super(User,self).__init__(*args,1)">kargs)
        self._meta.get_field(site_id').choices = get_site_choices()

    '

对于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的效果:

 

 

原文地址:https://www.cnblogs.com/AcAc-t

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有需要的朋友自行下载。
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。ViewSet在开发接口中不经常用。
一、Django介绍Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django 是一个开放源代码的 Web 应用框架,由 Python 写成。Django 遵守 BSD 版权,初次发布于 2005 年 7 月, 并于 2008 年 9 月发布了第一个正式版本 1.0 。Django学习线路Django 采用了 MVT 的软件设计模式,即模型(Model),视图(View)和模板(Template)。这个MVT模式并
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小白快速搭建django项目,并对可能出现的报错进行了分析
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的MysqlDB连接,Python3 支持支持pymysql 所有需要在app里面的__init__加上下面配置:
url: re_path('authors/$', views.AuthorView.as_view()), re_path('book/(?P\d+)/$', vie
前提 关于html寻找路线: template 如果在各个APP中存在, Django 会优先找全局template 文件下的html文件,如果全局下的template文件没有相关的html Djan
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
from bs4 import BeautifulSoup#kindeditordef kindeditor(request): s = ''' <li><s
view.py 配置 html 配置
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault('content_type&#
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
return HttpResponse("OK") 返回一个字符串 return redirect("/index/") 返回URL return render
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault('content_type&#
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况
自动发送 > 依赖jQuery文件 实例-->GET请求: 手动发送 > 依赖浏览器XML对象(也叫原生ajax) Ajax主要就是使用 【XmlHttpRequest】对象来完成请
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
return HttpResponse("OK") 返回一个字符串 return redirect("/index/") 返回URL return render