自定义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实现LRU算法的2种方法
Jun 24 Python
Python学习教程之常用的内置函数大全
Jul 14 Python
Python 高级专用类方法的实例详解
Sep 11 Python
Django中使用celery完成异步任务的示例代码
Jan 23 Python
和孩子一起学习python之变量命名规则
May 27 Python
对python GUI实现完美进度条的示例详解
Dec 13 Python
Python Opencv实现图像轮廓识别功能
Mar 23 Python
python 并发编程 非阻塞IO模型原理解析
Aug 20 Python
python 单线程和异步协程工作方式解析
Sep 28 Python
Python3 元组tuple入门基础
Feb 09 Python
python自动生成证件号的方法示例
Jan 14 Python
python基础之类属性和实例属性
Oct 24 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-Redis安装测试笔记
2015/03/05 PHP
PHP+Ajax+JS实现多图上传
2016/05/07 PHP
PHP获取日期对应星期、一周日期、星期开始与结束日期的方法
2018/06/22 PHP
js 数据类型转换总结笔记
2011/01/17 Javascript
关于jquery.validate1.9.0前台验证的使用介绍
2013/04/26 Javascript
jQuery on()方法使用技巧详解
2015/04/16 Javascript
使用canvas实现仿新浪微博头像截取上传功能
2015/09/02 Javascript
JavaScript位移运算符(无符号) >>> 三个大于号 的使用方法详解
2016/03/31 Javascript
Bootstrap Tree View简单而优雅的树结构组件实例解析
2017/06/15 Javascript
微信小程序选择图片和放大预览图片功能
2017/11/02 Javascript
使用JS代码实现俄罗斯方块游戏
2018/08/03 Javascript
微信小程序url传参写变量的方法
2018/08/09 Javascript
使用Node.js实现一个多人游戏服务器引擎
2019/03/13 Javascript
node读写Excel操作实例分析
2019/11/06 Javascript
vue2路由基本用法实例分析
2020/03/06 Javascript
[03:58]兄弟们,回来开黑了!DOTA2昔日战友招募宣传视频
2016/07/17 DOTA
Python使用百度API上传文件到百度网盘代码分享
2014/11/08 Python
Python实现向QQ群成员自动发邮件的方法
2014/11/19 Python
Django ORM框架的定时任务如何使用详解
2017/10/19 Python
浅谈numpy数组中冒号和负号的含义
2018/04/18 Python
在python中实现对list求和及求积
2018/11/14 Python
Python文件读写常见用法总结
2019/02/22 Python
PyCharm License Activation激活码失效问题的解决方法(图文详解)
2020/03/12 Python
基于SQLAlchemy实现操作MySQL并执行原生sql语句
2020/06/10 Python
英国最大的在线运动补充剂商店:Discount Supplements
2017/06/03 全球购物
YSL圣罗兰美妆俄罗斯官网:Yves Saint Lauret RU
2020/09/23 全球购物
信息管理专业推荐信
2013/10/29 职场文书
教育技术职业规划范文
2014/03/04 职场文书
物联网工程专业推荐信
2014/09/08 职场文书
中学生的1000字检讨书
2014/10/11 职场文书
2015年司法局工作总结
2015/05/22 职场文书
公司开业主持词
2015/07/02 职场文书
2015年信息技术教研组工作总结
2015/07/22 职场文书
matplotlib画混淆矩阵与正确率曲线的实例代码
2021/06/01 Python
Python标准库pathlib操作目录和文件
2021/11/20 Python
MySQL事务的ACID特性以及并发问题方案
2022/07/15 MySQL