自定义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实现将Excel转换为json的方法示例
Aug 05 Python
Python 打印中文字符的三种方法
Aug 14 Python
Python实现登陆文件验证方法
Oct 06 Python
Django model反向关联名称的方法
Dec 15 Python
Python两个字典键同值相加的几种方法
Mar 05 Python
使用python切片实现二维数组复制示例
Nov 26 Python
OpenCV中VideoCapture类的使用详解
Feb 14 Python
Python中的wordcloud库安装问题及解决方法
May 27 Python
浅谈优化Django ORM中的性能问题
Jul 09 Python
Python办公自动化之教你用Python批量识别发票并录入到Excel表格中
Jun 26 Python
解析目标检测之IoU
Jun 26 Python
Python数据处理的三个实用技巧分享
Apr 01 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 面向对象详解
2012/09/13 PHP
QQ互联一键登录审核不通过的解决方案
2014/09/10 PHP
PHP判断字符串长度的两种方法很实用
2015/09/22 PHP
PHP中文字符串截断无乱码解决方法
2016/10/10 PHP
Smarty日期时间操作方法示例
2016/11/15 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
2018/04/20 PHP
PHP通过bypass disable functions执行系统命令的方法汇总
2018/05/02 PHP
Laravel框架实现多数据库连接操作详解
2019/07/12 PHP
php 命名空间(namespace)原理与用法实例小结
2019/11/13 PHP
JavaScript 对Cookie 操作的封装小结
2009/12/31 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
js面向对象之静态方法和静态属性实例分析
2015/01/10 Javascript
javascript与jquery中的this关键字用法实例分析
2015/12/24 Javascript
easyui-datagrid特殊字符不能显示的处理方法
2017/04/12 Javascript
微信小程序tabBar底部导航中文注解api详解
2017/08/16 Javascript
input type=file 选择图片并且实现预览效果的实例
2017/10/26 Javascript
vue2.0 实现导航守卫的具体用法(路由守卫)
2018/05/17 Javascript
JS JQuery获取data-*属性值方法解析
2020/09/01 jQuery
python3大文件解压和基本操作
2017/12/15 Python
基于python list对象中嵌套元组使用sort时的排序方法
2018/04/18 Python
浅谈python在提示符下使用open打开文件失败的原因及解决方法
2018/11/30 Python
Python操作rabbitMQ的示例代码
2019/03/19 Python
详解Python解决抓取内容乱码问题(decode和encode解码)
2019/03/29 Python
Python设置matplotlib.plot的坐标轴刻度间隔以及刻度范围
2019/06/25 Python
python logging.basicConfig不生效的原因及解决
2020/02/20 Python
python实现TCP文件传输
2020/03/20 Python
150行Python代码实现带界面的数独游戏
2020/04/04 Python
美国帽子俱乐部商店:Hat Club
2019/07/05 全球购物
文秘人员工作职责
2014/01/31 职场文书
对祖国的寄语大全
2014/04/11 职场文书
慰问敬老院活动总结
2014/04/26 职场文书
选秀节目策划方案
2014/06/06 职场文书
党员个人剖析材料(四风问题)
2014/10/07 职场文书
群众路线个人整改方案
2014/10/25 职场文书
社团个人总结范文
2015/03/05 职场文书
制作能在nginx和IIS中使用的ssl证书
2021/06/21 Servers