def form_example_children_that_are_not_fields(request): def on_submit(form, **_): if not form.is_valid(): return return html.pre(f"You posted: {form.apply(Struct())}").bind(request=request) def post_validation(form, **_): if form.is_valid(): if form.fields.f1.value + form.fields.f2.value != form.fields.f3.value: form.add_error("Calculate again!") return Form( iommi_style="bulma", title="Children that are not fields", fields__name=Field(), fields__color=Field.choice(choices=['Red', 'Green', 'Blue']), fields__in_box=html.div( children__f1=Field.integer(attrs__class__column=True), children__plus=html.span("+", attrs__class={'column': True, 'is-narrow': True}), children__f2=Field.integer(attrs__class__column=True,), children__equals=html.span("=", attrs__class={'column': True, 'is-narrow': True}), children__f3=Field.integer(attrs__class_column=True), iommi_style="bulma_query_form", attrs__class={'box': True, 'columns': True, 'is-vcentered': True} ), post_validation=post_validation, actions__submit__post_handler=on_submit )
class FruitForm(Form): class Meta: @staticmethod def post_validation(form, **_): # Notice that post_validation is run, even if there are invalid fields, # so you either have to check that fields that you are interested in # are not None, or alternatively if you only want to run your validation if all fields # passed their individual checks you can just call form.is_valid (see below). # BUT when form.is_valid is called outside of a Form's post_validation # handler its result includes errors caused by the post_validation (as you # would expect). if form.is_valid( ) and form.fields.name.value == "tomato" and form.fields.color.value == "Blue": # Or alternatively call form.add_error raise ValidationError("Tomatoes are not blue") @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): return html.pre(f"You posted: {form.apply(Struct())}" ).bind(request=request) name = Field() amount = Field.integer() color = Field.choice(choices=['Red', 'Green', 'Blue'], )
class MyForm(Form): name = Field() color = Field.choice(choices=['Red', 'Green', 'Blue']) in_a_box = html.div( children__f1=Field.integer(attrs__class__column=True), children__plus=html.span("+", attrs__class={ 'column': True, 'is-narrow': True }), children__f2=Field.integer(attrs__class__column=True, ), children__equals=html.span("=", attrs__class={ 'column': True, 'is-narrow': True }), children__f3=Field.integer(attrs__class_column=True), iommi_style="bulma_query_form", attrs__class={ 'box': True, 'columns': True, 'is-vcentered': True }) class Meta: iommi_style = "bulma" title = "Children that are not fields" post_validation = post_valid actions__submit__post_handler = on_submit
class ChangeSubscriptionForm(Form): choices = Field.radio( choices=[subscribed, unsubscribed], initial=unsubscribed if subscription is None else subscribed, display_name='') passive = Field.boolean( display_name='Show only when unread', initial=subscription and subscription.subscription_type == 'passive') identifier = Field.hidden(initial=identifier_) class Meta: title = 'Change subscription' def actions__submit__post_handler(form, **_): subscription_type = 'passive' if form.fields.passive.value else 'active' if form.fields.choices.value == subscribed: if subscription is None: Subscription.objects.create( user=request.user, identifier=identifier_, subscription_type=subscription_type, ) else: subscription.subscription_type = subscription_type subscription.save() else: if subscription: subscription.delete() else: pass # already unsubscribed
class FruitForm(Form): class Meta: @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): return html.pre(f"You posted: {form.apply(Struct())}" ).bind(request=request) name = Field() amount = Field.integer() color = Field.choice(choices=['Red', 'Green', 'Blue'], )
class DateRangeField(Form): first_day = Field.date() last_day = Field.date() class Meta: @staticmethod def post_validation(form, **_): print("post validation", form.is_valid()) if form.is_valid(): if form.fields.first_day.value > form.fields.last_day.value: form.add_error("First day must be <= last day")
def test_field_from_model_factory_error_message(): from django.db.models import Field as DjangoField, Model class CustomField(DjangoField): pass class FooFromModelTestModel(Model): foo = CustomField() with pytest.raises(AssertionError) as error: Field.from_model(FooFromModelTestModel, 'foo') assert str(error.value) == "No factory for CustomField. Register a factory with register_factory or register_field_factory, you can also register one that returns None to not handle this field type"
class MyPage(Page): header = Fragment() some_form = Form(fields=Namespace(fisk=Field(), )) some_other_form = Form(fields=Namespace( fjomp=Field(), fisk=Field(), )) a_table = Table( model=TFoo, columns=Namespace( columns=Column(), fusk=Column(attr='b', filter__include=True), ), )
class KitchenForm(Form): kitchen_foo = Field() fisk = Field.multi_choice( choices=[1, 2, 3, 4], parse=choice_parse, initial=[1, 2], editable=False ) textarea = Field.textarea(initial='initial value') radio = Field.radio(choices=['foo!!_"', 'bar', 'baz']) checkbox = Field.boolean() date = Field.date() choice = Field.choice(choices=['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'X']) choice_with_groups = Field.choice( choices=['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'X'], choice_to_optgroup=lambda choice, **_: choice[0] if choice[0].islower() else None )
class ChangePasswordForm(Form): class Meta: title = gettext('Change password') @staticmethod def actions__submit__post_handler(form, request, **_): if form.is_valid(): user = request.user user.set_password(form.fields.new_password.value) user.save() return HttpResponseRedirect('..') current_password = Field.password(is_valid=current_password__is_valid, display_name=gettext('Current password')) new_password = Field.password(is_valid=new_password__is_valid, display_name=gettext('New password')) confirm_password = Field.password(is_valid=confirm_password__is_valid, display_name=gettext('Confirm password'))
def test_post_not_trigger_bind(): p = Page( parts=dict( form=Form( fields__foo=Field(), ), exploding_form=ExplodingForm(), ) ) p = p.bind( request=req( 'post', **{ '-': '', 'foo': 'bar', }, ) ) assert p.parts.form.fields.foo.value == 'bar' with pytest.raises(Exception) as e: # noinspection PyStatementEffect p.parts.exploding_form assert str(e.value) == 'Boom'
class ForgotPasswordForm(Form): username_or_email = Field( is_valid=lambda parsed_data, **_: (parsed_data is not None, 'Unknown username or email'), parse=parse) class Meta: title = 'Request password reset' actions__submit__display_name = 'Send reset email' def actions__submit__post_handler(form, **_): if not form.is_valid(): return user = form.fields.username_or_email.value code = token_hex(64) ResetCode.objects.filter(user=user).delete() ResetCode.objects.create(user=user, code=code) send_mail( subject=f'{settings.INSTALLATION_NAME} password reset', message=f"Your reset code is: \n{code}", from_email=settings.NO_REPLY_EMAIL, recipient_list=[user.email], ) return HttpResponseRedirect(reverse(reset_password))
class FileForm(Form): upload = Field.file() class Meta: @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): print(f"Uploaded {len(form.fields.upload.value)} bytes")
class LoginForm(Form): username = Field() password = Field.password() next = Field.hidden(initial=request.GET.get('next', '/')) class Meta: title = 'Login' def actions__submit__post_handler(form, **_): if 'user' in form.extra: login(request, form.extra.user) return HttpResponseRedirect(form.fields['next'].value or '/') def is_valid(self): if not super(LoginForm, self).is_valid(): return False username = self.fields['username'].value password = self.fields['password'].value if username and password: try: user = User.objects.get(username=username) except User.DoesNotExist: return False self.extra.user = user if authenticate(request=request, username=username, password=password): return True try: username = User.objects.get(username=username) if b64encode(sha1(password.encode()).digest()).decode( ) == user.password: user.set_password(password) # upgrade password user.save() authenticate(request=request, username=username, password=password) except User.DoesNotExist: pass return False
def extra_fields(request): class FooTable(Table): name = Column(filter__include=True) table = FooTable(rows=Foo.objects.all(), query__form__fields__my_extra_field=Field( attr=None, initial="Hello World")).bind(request=request) print(table.query.form.fields.my_extra_field.value) return table
class FruitForm(Form): class Meta: @staticmethod def post_validation(form, **_): # Notice that post_validation is run, even if there are invalid fields # hence the 'or' below if (form.fields.name.value or '').lower( ) == "tomato" and form.fields.color.value == "Blue": # Or alternatively call form.add_error raise ValidationError("Tomatoes are not blue") @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): return html.pre(f"You posted: {form.apply(Struct())}" ).bind(request=request) name = Field() amount = Field.integer() color = Field.choice(choices=['Red', 'Green', 'Blue'], )
class MyForm(Form): event = Field() # attr='' => instance.first_day, instance.last_day instead of instance.when.first_day, instance.when.last_day when = DateRangeField(attr='') class Meta: @staticmethod def actions__submit__post_handler(form, **_): if not form.is_valid(): return return html.pre(f"You posted {form.apply(Struct())}").bind(request=request)
def create_issue(request, project_name): project = Project.objects.get(name=project_name) def post_handler(form, **kwargs): result = create_object__post_handler(form=form, **kwargs) if form.is_valid(): form.instance.comments = Room.objects.create( name=f'Issue comments {project}/{form.instance}', custom_data=f'issues/{project.pk}/{form.instance.pk}') form.instance.save() return result return Form.create( auto__model=Issue, auto__exclude=['time_created', 'last_changed_time', 'comments'], fields__project=Field.hidden(editable=False, initial=project), fields__last_changed_by=Field.hidden(editable=False, initial=request.user), actions__submit__post_handler=post_handler, )
class LoginForm(Form): username = Field(display_name=gettext('Username')) password = Field.password(display_name=gettext('Password')) class Meta: title = gettext('Login') @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): user = auth.authenticate( username=form.fields.username.value, password=form.fields.password.value, ) if user is not None: request = form.get_request() auth.login(request, user) return HttpResponseRedirect(request.GET.get('next', '/')) form.add_error(gettext('Unknown username or password'))
class SubmitForm(Form): short = Field(initial=random_short(), is_valid=lambda parsed_data, **_: (not Entry.objects.filter(short=parsed_data.strip()). exists(), 'Short name already in use')) url = Field( is_valid=lambda parsed_data, **_: (not Entry.objects.filter( url=parsed_data.strip()).exists(), 'URL already submitted')) class Meta: @staticmethod def actions__submit__post_handler(form, **_): if form.is_valid(): entry = Entry( short=form.fields.short.value, url=form.fields.url.value, created_at=timezone.now(), valid_to=timezone.now() + timedelta(days=30), ) entry.save() return HttpResponseRedirect(f'/thanks/{entry.short}')
class ResetPasswordForm(Form): reset_code = Field( is_valid=lambda parsed_data, **_: (parsed_data is not None, 'Invalid reset password code'), parse=parse) new_password = Field.password() confirm_password = Field.password( is_valid=lambda parsed_data, **_: (parsed_data == request.POST.get( 'new_password'), 'Passwords do not match')) class Meta: title = 'Reset password' def actions__submit__post_handler(form, **_): if form.is_valid(): reset_code = form.fields.reset_code.value reset_code.user.set_password( form.fields.new_password.value) login(request, reset_code.user) reset_code.delete() return HttpResponseRedirect('/')
def vote(request, question_id): # question = get_object_or_404(Question, pk=question_id) # try: # selected_choice = question.choice_set.get(pk=request.POST['choice']) # except (KeyError, Choice.DoesNotExist): # # Redisplay the question voting form. # return render(request, 'polls/detail.html', { # 'question': question, # 'error_message': "You didn't select a choice.", # }) # else: # selected_choice.votes += 1 # selected_choice.save() # # Always return an HttpResponseRedirect after successfully dealing # # with POST data. This prevents data from being posted twice if a # # user hits the Back button. # return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) # <h1>{{ question.question_text }}</h1> # # {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} # # <form action="{% url 'polls:vote' question.id %}" method="post"> # {% csrf_token %} # {% for choice in question.choice_set.all %} # <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> # <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> # {% endfor %} # <input type="submit" value="Vote"> # </form> question = get_object_or_404(Question, pk=question_id) def post_handler(form, **_): if form.is_valid(): choice = form.fields.choice.value choice.votes += 1 choice.save() return HttpResponseRedirect( reverse('polls:results', args=(question.id, ))) return Form( title=str(question), fields__choice=Field.choice_queryset(question.choice_set.all()), actions__submit__post_handler=post_handler, )
class MyForm(Form): class Meta: iommi_style = 'bootstrap' foo = Field.boolean()
class TrackForm(Form): artist = Field.choice_queryset(choices=Track.objects.all())
class FruitForm(Form): name = Field() amount = Field.integer() color = Field.choice(choices=['Red', 'Green', 'Blue'], )
class SinkForm(Form): foo = Field()
class MyForm(Form): my_field = Field(extra__foo=17, )
class MyForm(Form): my_field = Field.choice(choices=[], )