Add property to one of the form fields in django - python

I am trying to add a special template property to one of the form fields which I will than use to render the form in template tag. Here is the code:
form = ProfileForm()
for field in form:
if field.name == 'email':
field.template = 'email_field.html'
This way, original form variable is not modified. Is there a way to achive my goal?

I'm going to assume you might want to build a html5 email field:
from django import forms
from django.forms.widgets import Widget
from django.utils.safestring import mark_safe
class Html5Email(Widget):
def render(self, name, value, attrs=None):
return mark_safe(u'<input name="custom-email" type="email" />')
class YourForm(forms.Form):
html5_email = forms.CharField(widget=Html5Email())
I came up with the above by glancing at the Django source code. Since I haven't personally use the above in an actual project, the code will probably need to be fleshed out.

Related

How does StringField in WTForms Create Fields in HTML File

I'm a beginner in coding and currently learning Python. I have been using Flask and WTForms recently to create a registration form. Besides just following tutorials to build the form, I'm also trying to understand it a little bit and see how it works (just generally). So my question is about the StringField.
I have created an html file called registr.html and it will be rendered. Inside of this html file, there is two lines of code that will create a field for the user to input their username, see below:
{{ form.username.label }}
{{ form.username }}
And in my Python application, I have created something below, say Section A:
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
And below, say Section B:
#app.route("/register", methods=['GET', 'POST'])
def register():
form = RegistrationForm()
return render_template('register.html', title='Register', form=form)
Here is my question. I understand form.username.label will put the label "Username" above the input field so people know this is where they input their username. And then I think what form.username does is actually creating a field so people can enter something in there. So my understanding is that username is an attribute that is equal to StringField('Username', validators=[DataRequired()]), which is an object of class StringField, and since form is equal to RegistrationForm(), So executing form.username in the html file is like executing Registration.StringField('Username', validators=[DataRequired()]). Am I correct, here? If so, how executing an object StringField('Username', validators=[DataRequired()]) can create an input field in the html? Can we execute an object? I think we can only execute a method in a class, correct? So there must be something else going on that I don't understand. Again I'm still a beginner and learning Python. So any help is be greatly appreciated!
there is a default render widget. You can overwrite the widget if you need custom HTML to be rendered (https://wtforms.readthedocs.io/en/stable/widgets.html). The specific the render widget used is here:
class Input(object):
"""
Render a basic ``<input>`` field.
This is used as the basis for most of the other input fields.
By default, the `_value()` method will be called upon the associated field
to provide the ``value=`` HTML attribute.
"""
html_params = staticmethod(html_params)
def __init__(self, input_type=None):
if input_type is not None:
self.input_type = input_type
def __call__(self, field, **kwargs):
kwargs.setdefault("id", field.id)
kwargs.setdefault("type", self.input_type)
if "value" not in kwargs:
kwargs["value"] = field._value()
if "required" not in kwargs and "required" in getattr(field, "flags", []):
kwargs["required"] = True
return Markup("<input %s>" % self.html_params(name=field.name, **kwargs))

Passing a variable into a WTForms class

I'm relatively inexperienced with Python and Flask, and am stuck trying to pass a variable to a WTForms class.
Here's what I have:
views.py
#app.route('/teacher/tasks/new')
#login_required
def new_hw_task():
classes = Class.query.filter_by(userid=current_user.userid).all()
form = NewTaskForm(classes = classes)
return render_template('/teacher/new_hw_task.html', form=form)
forms.py
class NewTaskForm(FlaskForm):
classes = SelectMultipleField('Select classes to assign this homework to', choices = [("1", "Class 1"), ("2","Class 2")])
new_hw_task.html
<div class="form-group">
{{ form.classes.label }}
{{ form.classes(class_="form-control selectpicker", placeholder=form.classes.description, title="Select at least one class to assign", show_tick=true)}}
</div>
I want the classes variable (an instance of a Class class defined in models.py - yes, yes, I know how sloppy it is to have a class called 'Class') to be accessible in forms.py so that I can replace the choices in the SelectMultipleField with ones from classes. However, I can't find a way to pass it through (you can see that I've tried putting classes=classes into the parentheses after NewTaskForm).
Actually, my preferred way to do this would be to simply access current_user (the session-based object set by flask_login) from within forms.py, but I appear to be unable to do that either, even if I import current_user at the top of the file.
Is anybody able to explain to me where I'm going wrong here, please?
The WTForms documentation for SelectField explains how to pass variables into a form from a view. It's as simple as assigning a list of choices to form.field.choices. In turn, you remove the choices= keyword argument from the field constructor.
Adapted for your case, it would look like this.
#app.route('/teacher/tasks/new')
#login_required
def new_hw_task():
classes = Class.query.filter_by(userid=current_user.userid).all()
form = NewTaskForm()
form.classes.choices = classes
return render_template('/teacher/new_hw_task.html', form=form)

How to use Django AutoField to edit a modelForm?

The Django doc mention that a Model AutoField will not be represented in a form built with a ModelForm.
When editing and saving that form, how should I supposed to know the underlying AutoField id value to save correctly my form data to database?
I know I can inject myself in the edit form an hidden field to know which row has been edited but is there a way Django manage that hidden field or some other mecanism automatically?
Thanks a lot
Etienne
You do that by specifying the instance=<> parameter when you are using ModelForm.
More on this in the documentation here
Example usage of a create/update view:
def myview(request, id=None):
if id:
obj_to_edit = MyModel.objects.get(id=1)
form = MyForm(instance=obj_to_edit)
else:
obj_to_edit = None
form = MyForm()
if request.method == 'POST':
if id: #update
form = MyForm(request.POST, instance=obj_to_edit)
else: #create
form = MyForm(request.POST)
#rest of the code
and the URL would have something like:
url(r'/blah/create/', 'myview'),
url(r'/blah/edit/(?P<id>[\d+])/', 'myview')
Now, django understands that it needs to edit rather than create new objects.
Also note that if you are using forms.Form, you would have to manually query for the unique fields, or inject the hidden id field as you have mentioned.
Usually when you're editing a form the specific instance that you want to edit will be identified in your URL using either the primary key or a slug field, e.g:
www.example.com/model/edit/6/
or
www.example.com/model/edit/object_slug/
You would then set up your urls.py to pass that parameter to your view, where you would use the example provided by karthkir (I'll use the primary as the example from here)
urls.py
urlpatterns = patterns('',
url(regex=r'^model/edit/(?P<pk>\d+)/$', 'myapp.views.myview', name='add_customer'),
)
views.py
def myview(request, pk):
obj_to_edit = MyModel.objects.get(id=pk)
...

How can I disable the wtforms SelectField choices validation?

I have a wtforms form
class MyForm(Form):
names = SelectField('name', choices=[])
The choices of names field is built dynamically and rendered in the template by an ajax call. When I submit the form, it raises an exception "not a valid choice". I don't want the form to validate the choices of names field for me. How can I disable the validation?
I did something like this to step around the SelectMultipleField validation in WTForms. It should work the same way with a plain SelectField
class NonValidatingSelectMultipleField(SelectMultipleField):
"""
Attempt to make an open ended select multiple field that can accept dynamic
choices added by the browser.
"""
def pre_validate(self, form):
pass
I simply override the built-in validation.
I was stuck with the same issue. The solution provided by Xealot is great. I found that there is an option to set validation to False using validate_choice=False. I have included an example of both the solutions below.
class NonValidatingSelectField(SelectField):
"""
Attempt to make an open ended select multiple field that can accept dynamic
choices added by the browser.
"""
def pre_validate(self, form):
pass
class MyForm(Form):
names = NonValidatingSelectField('name')
names2 = SelectField('name2', validate_choice=False)
By "I don't want the form to validate the choices", I assume you actually mean "I'm going to do it myself later and doubt the form's ability to do it correctly".
But you are in luck! You can subclass an existing form to add choices dynamically.
class MyForm(Form):
# other fields...
def some_handler(request):
name_choices = build_name_choices()
class RealForm(MyForm):
names = SelectField('name', choices=name_choices)
form = RealForm(request.GET)
form.validate()
This also saves you from the tedium of merging the form's validation and error messages with those you generate yourself later.

Insert Header in Django form

I would like to insert a header in a Django form. I have the following fields:
Name
Price
Optional - Size
Optional - Color
But instead of having the "Optional - " in every optional item, I would like a header, so the form looks like this:
Name
Example
Optional fields:
Size
Color
(This is pseudocode but should be easy to illustrate my point)
I know i can render each individual form field in the HTML, but I would like to still use the {{ form.as_p }} (so I don't have to change the markup for every new field I want to add). Is there any way to define a Django property for the form so I can preserve the form.as_p and still have this additional header (and more headers for more sections of fields)?
Thank you
I made it with JQuery.
It is very simple.
$('#id_size').parent().parent().before('<h1>optional</h1>');
Well, for lack of a better option, I solved this problem by rendering the form's individual fields instead of the whole form.
Then I only have to do:
<div class="fieldWrapper">
(...Field 1...)
</div>
<h1>My Own Header</h1>
<div class="fieldWrapper">
(...Field 2...)
</div>
I think Django hasn't such functionality but django-uni-form has :) This is an example from uni-form documentation with small changes:
from uni_form.helper import FormHelper
from uni_form.layout import Layout, Fieldset
class ExampleForm(forms.Form):
[...]
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
'name',
'price'
),
Fieldset(
'Optional',
'size',
'color'
),
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
return super(ExampleForm, self).__init__(*args, **kwargs)
Quite an outdated post, but I spent several hours in finding a solution, so I would like to share it. Hope it's useful.
In your apps directory create a file named widgets.py, with following content, to extend the basic Widget class from Django:
# widgets.py
from django.forms.widgets import Widget
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
class HeaderWidget(Widget):
def __init__(self, attrs=None, label=None, tag='h1'):
self.label = label
self.tag = tag
super(HeaderWidget, self).__init__(attrs)
def render(self, name, value, attrs=None):
# change blocks/ according to your template path. In this case was templates/block
widget = render_to_string("blocks/header-form-field.html", {
'tag' : self.tag,
'label' : self.label,
})
return widget
Then create a file customfileds.py . Here we extend the Field Class with mostly nothing. The important thing is to avoid field validation, ase we have no input.
from django import forms
from django.forms.fields import Field
from . import widgets
class HeaderField(Field):
widget = widgets.HeaderWidget
# This is to avoid validation
validators = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
def clean(self, value=''):
"""
It seem the clean method in mandatory when creating a Field class.
Jaust return value without validation
"""
return value
Then create the html template. Put it in a path that matches your
widget = render_to_string("blocks/header-form-field.html"
#header-form-field.html
<{{ tag }} class="your-custom-class">{{ label }}</{{ tag }}>
Now you can add to your forms any HeaderField you need, like that:
class MyForm(GenericForm):
header1 = customfileds.HeaderField(label=_(""),required=False,label_suffix='',
widget=widgets.HeaderWidget(label=_("My custom Label text here"),tag="h3"))
field 1 = whatever input field you have...
Here you can find same code in a gita page
https://gitlab.com/MaadiX/header-field-for-django-forms/blob/master/README.md

Categories

Resources