自定义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实现通过shelve修改对象实例
Sep 26 Python
python使用opencv进行人脸识别
Apr 07 Python
Python实现输出程序执行进度百分比的方法
Sep 16 Python
快速了解python leveldb
Jan 18 Python
对Python中class和instance以及self的用法详解
Jun 26 Python
python flask框架实现重定向功能示例
Jul 02 Python
Python3开发环境搭建详细教程
Jun 18 Python
浅谈Python中的生成器和迭代器
Jun 19 Python
Python使用itcaht库实现微信自动收发消息功能
Jul 13 Python
如何基于Python实现word文档重新排版
Sep 29 Python
python 爬虫如何实现百度翻译
Nov 16 Python
解决Django transaction进行事务管理踩过的坑
Apr 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 数据库树的遍历方法
2009/02/06 PHP
thinkphp实现发送邮件密码找回功能实例
2014/12/01 PHP
微信公众号开发之通过接口删除菜单
2017/02/20 PHP
jquery 学习之二 属性 文本与值(text,val)
2010/11/25 Javascript
jQuery 1.5最新版本的改进细节分析
2011/01/19 Javascript
jquery mobile changepage的三种传参方法介绍
2013/09/13 Javascript
微信小程序后台解密用户数据实例详解
2017/06/28 Javascript
nodejs 子进程正确的打开方式
2017/07/03 NodeJs
解决angular2在双向数据绑定时[(ngModel)]无法使用的问题
2018/09/13 Javascript
Vue框架里使用Swiper的方法示例
2018/09/20 Javascript
jQuery实现的简单歌词滚动功能示例
2019/01/07 jQuery
谈谈node.js中的模块系统
2020/09/01 Javascript
React Native登录之指纹登录篇的示例代码
2020/11/03 Javascript
Python中使用动态变量名的方法
2014/05/06 Python
python字符串排序方法
2014/08/29 Python
Python实现二叉搜索树
2016/02/03 Python
python用Pygal如何生成漂亮的SVG图像详解
2017/02/10 Python
python遍历文件夹,指定遍历深度与忽略目录的方法
2018/07/11 Python
如何用python写一个简单的词法分析器
2018/12/18 Python
python3.6生成器yield用法实例分析
2019/08/23 Python
详解Django CAS 解决方案
2019/10/30 Python
Pytorch根据layers的name冻结训练方式
2020/01/06 Python
Python日志syslog使用原理详解
2020/02/18 Python
Python xpath表达式如何实现数据处理
2020/06/13 Python
phpquery中文手册
2021/03/18 PHP
苹果香港官方商城:Apple香港
2016/09/14 全球购物
教师自我反思材料
2014/02/14 职场文书
正风肃纪剖析材料
2014/02/18 职场文书
股指期货心得体会
2014/09/13 职场文书
党员先进性教育整改措施
2014/09/18 职场文书
幼儿园三八妇女节活动总结
2015/02/06 职场文书
2015秋季开学典礼致辞
2015/07/16 职场文书
求职信:求职应该注意的问题
2019/04/24 职场文书
入党转正申请书范文
2019/05/20 职场文书
导游词范文之颐和园/重庆/云台山
2019/09/10 职场文书
python开发飞机大战游戏
2021/07/15 Python