自定义django admin model表单提交的例子


Posted in Python onAugust 23, 2019

如下所示:

自定义django admin model表单提交的例子

希望可以从对admin提交的密码加密,并验证电话号码均为数字。

查看admin.py

from django.contrib import admin
class courseAdmin(admin.ModelAdmin)

我们自定义的管理类,继承与admin.ModelAdmin

查看对应admin模块对应源码

__init__.py

from django.contrib.admin.options import (
 HORIZONTAL, VERTICAL, ModelAdmin, StackedInline, TabularInline,FaultyAdmin,
)

从django.contrib.admin.options导入 ModelAdmin



options.py ModelAdmin源码比较长,就不全部列出了,看比较关键的地方

def get_urls(self):
  from django.conf.urls import url

  def wrap(view):
   def wrapper(*args, **kwargs):
    return self.admin_site.admin_view(view)(*args, **kwargs)
   wrapper.model_admin = self
   return update_wrapper(wrapper, view)

  info = self.model._meta.app_label, self.model._meta.model_name

  urlpatterns = [
   url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info),
   url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info),
   url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info),
   url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info),
   url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
   # For backwards compatibility (was the change url before 1.9)
   url(r'^(.+)/$', wrap(RedirectView.as_view(
    pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
   ))),
  ]
  return urlpatterns

可以看到add操作,交由add_view函数

def add_view(self, request, form_url='', extra_context=None):
  return self.changeform_view(request, None, form_url, extra_context)
@csrf_protect_m
 def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
  with transaction.atomic(using=router.db_for_write(self.model)):
   return self._changeform_view(request, object_id, form_url, extra_context)

 def _changeform_view(self, request, object_id, form_url, extra_context):
  to_field = request.POST.get(TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR))
  if to_field and not self.to_field_allowed(request, to_field):
   raise DisallowedModelAdminToField("The field %s cannot be referenced." % to_field)

  model = self.model
  opts = model._meta

  if request.method == 'POST' and '_saveasnew' in request.POST:
   object_id = None

  add = object_id is None

  if add:
   if not self.has_add_permission(request):
    raise PermissionDenied
   obj = None

  else:
   obj = self.get_object(request, unquote(object_id), to_field)

   if not self.has_change_permission(request, obj):
    raise PermissionDenied

   if obj is None:
    return self._get_obj_does_not_exist_redirect(request, opts, object_id)

  ModelForm = self.get_form(request, obj)
  if request.method == 'POST':
   form = ModelForm(request.POST, request.FILES, instance=obj)
   if form.is_valid():
    form_validated = True
    new_object = self.save_form(request, form, change=not add)
   else:
    form_validated = False
    new_object = form.instance
   formsets, inline_instances = self._create_formsets(request, new_object, change=not add)
   if all_valid(formsets) and form_validated:
    self.save_model(request, new_object, form, not add)
    self.save_related(request, form, formsets, not add)
    change_message = self.construct_change_message(request, form, formsets, add)
    if add:
     self.log_addition(request, new_object, change_message)
     return self.response_add(request, new_object)
    else:
     self.log_change(request, new_object, change_message)
     return self.response_change(request, new_object)
   else:
    form_validated = False
  else:
   if add:
    initial = self.get_changeform_initial_data(request)
    form = ModelForm(initial=initial)
    formsets, inline_instances = self._create_formsets(request, form.instance, change=False)
   else:
    form = ModelForm(instance=obj)
    formsets, inline_instances = self._create_formsets(request, obj, change=True)

  adminForm = helpers.AdminForm(
   form,
   list(self.get_fieldsets(request, obj)),
   self.get_prepopulated_fields(request, obj),
   self.get_readonly_fields(request, obj),
   model_admin=self)
  media = self.media + adminForm.media

  inline_formsets = self.get_inline_formsets(request, formsets, inline_instances, obj)
  for inline_formset in inline_formsets:
   media = media + inline_formset.media

  context = dict(
   self.admin_site.each_context(request),
   title=(_('Add %s') if add else _('Change %s')) % force_text(opts.verbose_name),
   adminform=adminForm,
   object_id=object_id,
   original=obj,
   is_popup=(IS_POPUP_VAR in request.POST or
      IS_POPUP_VAR in request.GET),
   to_field=to_field,
   media=media,
   inline_admin_formsets=inline_formsets,
   errors=helpers.AdminErrorList(form, formsets),
   preserved_filters=self.get_preserved_filters(request),
  )

  # Hide the "Save" and "Save and continue" buttons if "Save as New" was
  # previously chosen to prevent the interface from getting confusing.
  if request.method == 'POST' and not form_validated and "_saveasnew" in request.POST:
   context['show_save'] = False
   context['show_save_and_continue'] = False
   # Use the change template instead of the add template.
   add = False

  context.update(extra_context or {})




form = ModelForm(request.POST, request.FILES, instance=obj)

这里找到form表单的内容

form.is_valid()

验证表单内容是否合法,查看这个函数

首先找到ModelForm类

django\forms\models.py

class ModelForm(six.with_metaclass(ModelFormMetaclass, BaseModelForm)):
 pass

查看BaseModelForm

class BaseModelForm(BaseForm):



django\forms\forms.py
class BaseForm(object):
 def is_valid(self):
  """
  Returns True if the form has no errors. Otherwise, False. If errors are
  being ignored, returns False.
  """

  return self.is_bound and not self.errors
  @property
 def errors(self):
  "Returns an ErrorDict for the data provided for the form"
  if self._errors is None:
   self.full_clean()
  return self._errors

def full_clean(self):
  """
  Cleans all of self.data and populates self._errors and
  self.cleaned_data.
  """
  self._errors = ErrorDict()
  if not self.is_bound: # Stop further processing.
   return
  self.cleaned_data = {}
  # If the form is permitted to be empty, and none of the form data has
  # changed from the initial data, short circuit any validation.
  if self.empty_permitted and not self.has_changed():
   return

  self._clean_fields()
  self._clean_form()
  self._post_clean()
 def _clean_fields(self):
  for name, field in self.fields.items():
   # value_from_datadict() gets the data from the data dictionaries.
   # Each widget type knows how to retrieve its own data, because some
   # widgets split data over several HTML fields.
   #print(type(name))
   print(name,field)
   if field.disabled:
    value = self.get_initial_for_field(field, name)
   else:
    value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
   try:
    if isinstance(field, FileField):
     initial = self.get_initial_for_field(field, name)
     value = field.clean(value, initial)
    else:
     value = field.clean(value)
    self.cleaned_data[name] = value
    if hasattr(self, 'clean_%s' % name):
     value = getattr(self, 'clean_%s' % name)()
     self.cleaned_data[name] = value
   except ValidationError as e:
    #print(e)
    self.add_error(name, e)

上面列出函数在表单验证的过程中,顺序调用,可以看到添加错误的主要函数为_clean_fields,虽然没有继续仔细查看,但感觉关键在于field.clean(value),对应的field在我们声明对应model类时会保存相应字段的信息,这里做检查,如果不符合,则raise ValidationError,符合的haul就把新的数据放入到表单的cleaned_data中。

这一段来自官网的教程,这里指出错误信息的关键字包括,null, blank, invalid, invalid_choice, unique, and unique_for_date。刚才的clean函数应该就是检查这些地方。

The error_messages argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override. Error message keys include null, blank, invalid, invalid_choice, unique, and unique_for_date. Additional error message keys are specified for each field in the Field types section below.

到了这一部,基本已经可以达到目的了,我们可以看到 self.add_error函数。

然后回到options.py的ModelAdmin,我们可以写一个类继承ModelAdmin,然后重写新类的_changeform_view函数,避免对其它部分造成影响。

重写部分如下:

if form.is_valid():
    form_validated = True
    if not re.match('\d+',form.data['tel']):
     form_validated=False
     form.add_error('tel','电话号码必须为纯数字')
    if not re.match('\d+',form.data['number']):
     form_validated=False
     form.add_error('number','学工号必须为纯数字')
    if not form_validated:
     new_object=form.instance
    else:
     passw=form.data['password']
     m=md5()
     m.update(passw.encode('utf-8'))
     form.data['password']=m.hexdigest()
     new_object = self.save_form(request, form, change=not add)

以上这篇自定义django admin model表单提交的例子就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 装饰器功能以及函数参数使用介绍
Jan 27 Python
Python中用于转换字母为小写的lower()方法使用简介
May 19 Python
python简单分割文件的方法
Jul 30 Python
举例讲解Python设计模式编程中对抽象工厂模式的运用
Mar 02 Python
python连接mongodb密码认证实例
Oct 16 Python
Python寻找两个有序数组的中位数实例详解
Dec 05 Python
Pandas DataFrame数据的更改、插入新增的列和行的方法
Jun 25 Python
快速解决vue.js 模板和jinja 模板冲突的问题
Jul 26 Python
PyQt5多线程刷新界面防假死示例
Dec 13 Python
将python依赖包打包成window下可执行文件bat方式
Dec 26 Python
django执行原始查询sql,并返回Dict字典例子
Apr 01 Python
Spring http服务远程调用实现过程解析
Jun 11 Python
django admin 自定义替换change页面模板的方法
Aug 23 #Python
解决python多行注释引发缩进错误的问题
Aug 23 #Python
详解使用PyInstaller将Pygame库编写的小游戏程序打包为exe文件
Aug 23 #Python
python如何保证输入键入数字的方法
Aug 23 #Python
对python while循环和双重循环的实例详解
Aug 23 #Python
python 进程 进程池 进程间通信实现解析
Aug 23 #Python
python实现的生成word文档功能示例
Aug 23 #Python
You might like
解析PHP留言本模块主要功能的函数说明(代码可实现)
2013/06/25 PHP
php封装db类连接sqlite3数据库的方法实例
2017/12/19 PHP
用dtree实现树形菜单 dtree使用说明
2011/10/17 Javascript
jQuery随机切换图片的小例子
2013/04/18 Javascript
JavaScript中一个奇葩的IE浏览器判断方法
2014/04/16 Javascript
基于jQuery插件jqzoom实现的图片放大镜效果示例
2017/01/23 Javascript
简单好用的nodejs 爬虫框架分享
2017/03/26 NodeJs
使用yeoman构建angular应用的方法
2017/08/14 Javascript
通过vue-cli来学习修改Webpack多环境配置和发布问题
2017/12/22 Javascript
bootstrap tooltips在 angularJS中的使用方法
2019/04/10 Javascript
对node通过fs模块判断文件是否是文件夹的实例讲解
2019/06/10 Javascript
JS中的算法与数据结构之栈(Stack)实例详解
2019/08/20 Javascript
vue draggable resizable gorkys与v-chart使用与总结
2019/09/05 Javascript
微信小程序防止多次点击跳转(函数节流)
2019/09/19 Javascript
nodejs中内置模块fs,path常见的用法说明
2020/11/07 NodeJs
VUE实现吸底按钮
2021/03/04 Vue.js
[02:14]DOTA2英雄基础教程 修补匠
2013/12/23 DOTA
Python检测网站链接是否已存在
2016/04/07 Python
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
Python 爬虫之超链接 url中含有中文出错及解决办法
2017/08/03 Python
python实现求解列表中元素的排列和组合问题
2018/03/15 Python
对python中的for循环和range内置函数详解
2018/04/17 Python
Python使用requests提交HTTP表单的方法
2018/12/26 Python
python 自动轨迹绘制的实例代码
2019/07/05 Python
Python使用requests模块爬取百度翻译
2020/08/25 Python
python向企业微信发送文字和图片消息的示例
2020/09/28 Python
基于python的opencv图像处理实现对斑马线的检测示例
2020/11/29 Python
css3 transform及原生js实现鼠标拖动3D立方体旋转
2016/06/20 HTML / CSS
缅甸网上购物:Shop.com.mm
2017/12/05 全球购物
银行内勤岗位职责
2014/04/09 职场文书
2014年体检中心工作总结
2014/12/23 职场文书
蜗居观后感
2015/06/11 职场文书
2019年世界儿童日宣传标语
2019/11/22 职场文书
Nginx 过滤静态资源文件的访问日志的实现
2021/03/31 Servers
python基础之爬虫入门
2021/05/10 Python
排查并解决Oracle sysaux表空间异常增长
2022/04/20 Oracle