Last active
February 17, 2018 03:58
-
-
Save raiderrobert/da081a219540c4d62ee1a764e3e91f44 to your computer and use it in GitHub Desktop.
DEP Draft - Django Forms API Rewrite
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Proposed New Forms API, not currently possible in Django Forms API (as of 2.0) | |
""" | |
from django.forms import ModelForm, ModelFormListField | |
from .models import Author, Book | |
# Make this work like serailization relationships in Django Rest Framework | |
# http://www.django-rest-framework.org/api-guide/relations/ | |
# or relationships in WTForms | |
# http://wtforms-alchemy.readthedocs.io/en/latest/relationships.html#one-to-many-relations | |
class BookForm(ModelForm): | |
class Meta: | |
model = Book | |
fields = ['name', 'published_date'] | |
class AuthorWithWorksForm(ModelForm): | |
works = ModelFormListField(BookForm) | |
class Meta: | |
model = Author | |
fields = ['name', 'works'] | |
# Allow for overrides on the form Meta rather than modification on __init__ | |
# follows WTForms http://wtforms-alchemy.readthedocs.io/en/latest/configuration.html | |
from django.forms.widgets import TextArea | |
from .validators import validate_in_past | |
class AuthorOnlyForm(ModelForm): | |
class Meta: | |
model = Author | |
fields = ['name', 'birth_date'] | |
field_args = { | |
'name': { | |
'widget': TextArea | |
}, | |
'birth_date': { | |
'required': True, | |
'validators': [validate_in_past] | |
} | |
} | |
# Provide a means for the form to be client-side validation aware | |
# Since there's no standard, this very naive implementation may not scale | |
# Here's an implementation of Parsley.js through the new proposed API | |
# http://parsleyjs.org/doc/index.html#usage-field | |
from django.utils.timezone import now | |
class BookForm(ModelForm): | |
class Meta: | |
model = Book | |
fields = ['name', 'published_date'] | |
field_args = { | |
'name': { | |
'widget_attrs': { | |
'data-parsley-minlength':'4' | |
} | |
}, | |
'birth_date': { | |
'required': True, | |
'validators': [validate_in_past], | |
'widget_attrs': { | |
'data-parsley-max': now().astimezone().date().isoformat() | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
class Author(models.Model): | |
name = models.CharField(max_length=255) | |
birth_date = models.DateField(blank=True, null=True) | |
def __str__(self): | |
return self.name | |
class Book(models.Model): | |
name = models.CharField(max_length=255) | |
published_date = models.DateField(blank=True, null=True) | |
authors = models.ManyToManyField( | |
Author, | |
on_delete=models.SET_NULL, | |
related_name='works' | |
) | |
def __str__(self): | |
return self.name | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @raiderrobert, I don't think this needs a DEP, it looks more like 3 independent tickets to me.
1/ is basically to turn
InlineFormset
into a form field. I quite like the idea.2/ is the wontfixed ticket #17924 and related to #20000.
With hindsight I regret not pushing harder for #17924 and settling for #20000. DRF allowing this and being so widely popular certainly leads to people assuming Django forms works the same. Using this feature extensively with DRF I often feel frustrated not having it for forms.
One of the challenge with this ticket will be how to provide a consistent API as Carl mentioned in https://code.djangoproject.com/ticket/20000#comment:14 :
widgets
,label
,help_text
anderror_messages
, all have first level attributes on theMeta
object, and deprecating them would be way too disruptive.The process for a wontfixed ticket is the take it to the mailing list.
3/ I'm guessing
widget_attrs
is targeting the<input>
tag in the generated HTML? Personally I'm not fond of the tight coupling of Python fields and HTML rendering, I prefer to look at form fields as a description of the data at a high level, then templates should have the whole object available to decide how to render the appropriate widget.Imo would be better solved with:
Of course that's much harder to do with DTL than Jinja2, and currently
form.birth_date
is aBoundField
rather than the actual field, but you get the idea.