如何更改ModelForm中所有Djangodate字段的默认控件?

给定一组典型的模型:

# Application A from django.db import models class TypicalModelA(models.Model): the_date = models.DateField() # Application B from django.db import models class TypicalModelB(models.Model): another_date = models.DateField() ... 

如何将所有 DateField的默认小部件更改为自定义MyDateWidget?

我问,因为我希望我的应用程序有一个jQueryUI datepickerinputdate。

我已经考虑了一个自定义字段,用我的自定义小部件来扩展django.db.models.DateField。 这是实施这种全面改变的最好方式吗? 这样的改变将需要特别地将特定的MyDateField导入到每个模型中,这是劳动密集型的,容易出现开发者错误(即,less数模型.DateField将通过),并且在我的脑海中似乎是不必要的重复努力。 另一方面,我不喜欢修改models.DateField的规范版本。

感谢和意见。

您可以在ModelForm类上声明一个名为formfield_callback的属性。 这应该是一个函数,它将Django模型的Field实例作为参数,并返回一个表单Field实例来表示它的forms。

然后,您只需要查看传入的模型字段是否为DateField的实例,如果是,则返回您的自定义字段/小部件。 如果不是,模型字段将有一个名为formfield的方法,您可以调用它来返回其默认的表单字段。

所以,像这样的:

 def make_custom_datefield(f): if isinstance(f, models.DateField): # return form field with your custom widget here... else: return f.formfield() class SomeForm(forms.ModelForm) formfield_callback = make_custom_datefield class Meta: # normal modelform stuff here... 

那么,制作一个自定义模型领域只是为了改变它的默认表单部件并不是真正的开始。

你可以制作你自己的表单部件,并覆盖表单中的字段,像在Soviut的回答中那样指定你自己的部件。

还有一个更短的方法:

 class ArticleForm(ModelForm): pub_date = DateField(widget=MyDateWidget()) class Meta: model = Article 

有一个如何编写表单小部件的例子,它在Django的表单包中的某处。 这是一个3下拉dateselect器。

当我只想添加一些JavaScript到一个标准的HTMLinput元素时,我通常会做的事情就是保持原样,并且稍后通过JavaScript引用它的id来修改它。 您可以很容易地捕获Django生成的input字段的id的命名约定。

当您在窗体中覆盖它时,您也可以只提供该窗口小部件的类。 然后用类名抓住jQuery 。

这篇文章帮了我很多次。

它的肉涉及覆盖ModelForm的__init__方法,然后调用超类' __init__方法,然后单独调整字段。

 class PollForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(PollForm, self).__init__(*args, **kwargs) self.fields['question'].widget = forms.Textarea() class Meta: model = Poll 

这个方法看起来可能比Vasil更复杂,但它提供了额外的好处,就是能够精确地覆盖某个字段上的任何属性,而不用重新声明它来重新设置任何其他属性。

更新:build议的方法可以推广到更改所有date字段,而不必严格键入每个名称:

 from django.forms import fields as formfields from django.contrib.admin import widgets class PollForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(PollForm, self).__init__(*args, **kwargs) for field_name in self.fields: field = self.fields[field_name] if isinstance(field, formfields.DateField): field.widget = widgets.AdminDateWidget() class Meta: model = Poll 

这对我python3django 1.11

我使用JQuery。 您只需要查找要与dateselect器关联的字段的“id”,并将其与JQuery和正确的显示格式绑定:

models.py

 class ObjectForm(ModelForm): class Meta: model = Object fields = ['FieldName1','FieldName2'] 

在您使用视图呈现的页面顶部:

 <head> <link type="text/css" href="/media/css/ui-darkness/jquery-ui-1.8.2.custom.css" rel="Stylesheet" /> <script type="text/javascript" src="/media/js/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="/media/js/jquery-ui-1.8.2.custom.min.js"></script> </head> <script type="text/javascript"> $(function() { $("#id_FieldName1").datepicker({ dateFormat: 'yy-mm-dd' }); $("#id_FieldName2").datepicker({ dateFormat: 'yy-mm-dd' }); }); </script> ... {{form}} 

你确实想定义一个自定义小部件,并使用小部件的内部Media类来定义必须包含在页面中的JS(和CSS?)文件,以使小部件工作。 如果你这样做,你可以使你的部件完全独立和可重用。 查看django-markitup的例子 (它有一个可重复使用的MarkItUp!通用标记编辑器 )。

然后使用formfield_callback(请参阅James Bennett的答案)轻松地将该小部件应用到表单中的所有DateField。

有些人可能会对此皱眉,但用您的自定义小部件replacedateselect器我会为您的项目创build一个monkeypatch应用程序,并在运行时修补Django本身。 这样做的好处是任何第三方应用程序也将受到影响,因此向最终用户呈现统一的界面,而无需修改第三方代码:

 from django.forms.widgets import DateInput , DateTimeInput, TimeInput from FOO.widgets import MyjQueryWidget # be nice and tell you are patching logger.info("Patching 'DateInput.widget = MyjQueryWidget': Replaces django DateInput to use my new super 'MyjQueryWidget'") # be nicer and confirm signature of code we are patching and warn if it has changed - uncomment below to get the current hash fingerprint # raise Exception(hashlib.md5(inspect.getsource(DateInput.widget)).hexdigest()) # uncommet to find latest hash if not '<enter hexdigest fingerprint here>' == \ hashlib.md5(inspect.getsource(DateInput.widget)).hexdigest(): logger.warn("md5 signature of 'DateInput.widget' does not match Django 1.5. There is a slight chance patch " "might be broken so please compare and update this monkeypatch.") # be nicest and also update __doc__ DateInput.__doc__ = "*Monkeypatched by <app name>*: Replaced django DateInput.widget with my new super 'MyjQueryWidget'" + DateInput.__doc__ DateInput.widget = MyjQueryWidget 

以上是从我的html5monkeypatch作为我的项目的一部分启发,看看patch_widgets.py和patch_fields.py 。