Django form cache or reload issue - django

I have a page to insert value to db.
After inserting am loading another page with a drop down listing the db values
But the inserted value is not listing in dropdown
The problem is not with transaction/commit etc. The query to retrieve the data for the drop down in second form is correct.
Form1(first page)
class Organization(forms.Form):
orgList = getOrgUnitList()
orgUnit = forms.CharField(label=u'Organization Name',
max_length=50,
error_messages={'required':'Organization name is required field.'})
parentOrg= forms.ChoiceField(label=u'Parent Organization',
choices=[(u'Select',u'Select')]+orgList,
error_messages={'required':'Organization name is required field.'})
Form2(Second page)
class User(forms.Form):
orgUnitList = getOrgUnitList()
email = forms.EmailField(label=u'Email',
max_length=50,
error_messages={'required':'Email is required field'})
orgUnit = forms.ChoiceField(label=u'Organizational Unit',
choices=orgUnitList,
error_messages={'required':'Organizational unit is required field'})
Query
def getOrgUnitList():
orgUnitList = list(OrganizationUnit.objects.values_list
('OrgUnitID','OrgUnitName').order_by('OrgUnitName'))
return orgUnitList
but when i tried to bind the choices in view it is working
working code
*view*
def user()
template = get_template('AddUser.html')
form = AddUser()
orgUnitList = getOrgUnitList()
del objAdminUIDA
form.fields['orgUnit'].widget.choices=orgUnitList
variables = RequestContext(request,{'form':form})
output = template.render(variables)
del form
return HttpResponse(output)
But i cant give the dropdown choice in view i want to give choices in form.i need a solution for form2

Firstly, the orgList is evaluated in form definition, that's why choices don't change. You should place getOrgUnitList in form's __init__ (or in some other method).
Secondly, you don't pass any data to the form, may be you want
form = AddUser(request.POST or None)

Related

(Flask) WTForm gets rendered with wrong values

I am currently working on a web-application based "database-explorer" for a university project.
Basically I create a site for each relation of the database, where the user can view the data and additionally I want them to be able to add data.
For that I use wtforms. I take the inputs, create a simple "SQL string" with it and execute it.
To make the input easier, I want to use dynamic SelectFields.
This is my approute:
#app.route('/table/fact_angestellte')
def fact_angestellte():
if current_user.is_authenticated:
mycursor.execute("SELECT * FROM dim_rolle WHERE ro_rolle !='Ansprechpartner' AND ro_rolle != 'Teilnehmer';")
choicesRolle = mycursor.fetchall()
form = InsertAngestelltenForm(choicesRolle)
print(form.choicesRolle)
mycursor.execute("SELECT * FROM fact_angestellte INNER JOIN dim_rolle ON fact_angestellte.an_rolle_fk = dim_rolle.ro_id_pk;")
data = mycursor.fetchall()
return render_template('tables/fact_angestellte.html', data=data, form=form)
else:
return redirect(url_for('login'))
The form gets created successfully and if I try to print form.choicesRolle (in the approute), it also gives me the correct output in the console. But when I go on my website, the SelectField still has the default value of choicesRolle.
class InsertAngestelltenForm(FlaskForm):
choicesRolle =[]
nachname = StringField('Nachname', validators=[DataRequired()])
vorname = StringField('Vorname',validators=[DataRequired()])
geschlecht = SelectField('Geschlecht', choices=[('maennlich', 'männlich'), ('weiblich', 'weiblich')], validators=[DataRequired()])
postleitzahl = StringField('Postleitzahl | FK', validators=[DataRequired()])
strasse = StringField('Straße und Nummer', validators=[DataRequired()])
rolle = SelectField('Rolle', choices=choicesRolle, validators=[DataRequired()])
submit = SubmitField('Eintrag hinzufügen')
def __init__(self, choicesRolle):
super().__init__()
self.choicesRolle = choicesRolle
print(self.choicesRolle)
So my problem is: the object has the correct attributes, but somehow they don't "reach" the template.
Any help is appreciated.
Greetings
Per the WTForms documentation, the choices keyword is only evaluated once. In your example, this means it's evaluating to the empty array you set in the choicesRolle class attribute, and that's what's being passed to Flask. You need to set the choices after the form is instantiated, not during it.
On your form class, remove the entire __init__ method, the choicesRolle class attribute, and the choices parameter from the rolle SelectField. Then, in your fact_angestellte view function, set the form's choices after you instantiate it, as follows:
choicesRolle = mycursor.fetchall()
form = InsertAngestelltenForm()
form.rolle.choices = choicesRolle
This should work...let me know. Note that I'm not sure what data is being returned from mycursor.fetchall() as you don't really describe, but the SelectField choices needs to be a list of values...WTForms by default coerces each value to unicode.

Pass initial values to ChoiceField in django formset

I can't figure out how to populate a django ChoiceField with initial data. Preferrably want to do it in the view, as it will change depending on the parameters I pass to the view.
views.py
def index(request):
init_ingredients = [{'food':'Candy','amt':12,'units':'cup'},{'food':'Bacon','amt':9,'units':'cup'}]
IngredientsFormSet = formset_factory(IngredientLineForm, can_delete=True)
if request.method == 'POST':
formset = IngredientsFormSet(request.POST, request.FILES)
...
else:
formset = IngredientsFormSet(initial=init_ingredients)
the 'food' field and the 'amt' field populate, but the 'units' field - which is an html Select input does not populate with initial value. Do I need to define choices too? and have the initial value be one of them?
forms.py
class IngredientLineForm(forms.Form):
food = forms.CharField(widget=forms.TextInput(attrs={'class':'foods form-control'})) #class = food
units = forms.ChoiceField(widget=forms.Select(attrs={'class':'units form-control'}))
amt = forms.CharField(widget=forms.NumberInput(attrs={'class':'amt form-control'}))
I use:
class netadminGlobalFormView(LoginRequiredMixin, FormView):
model = netInfo
form_class = netInfoForm
def get_initial(self):
initial = super(netadminGlobalFormView, self).get_initial()
initial['eth0_ip'] = self.model_instance.get_eth0_ip_stdout
initial['config_type'] = 'DHCP'
return initial
Note that here:
initial['config_type'] = 'DHCP'
I set a value from selection:
# value displayed value
config_types=(
('DHCP', 'Automatic (DHCP)'),
('MANUAL', 'Static (manual)')
)
and form definition includes the following:
class netInfoForm(ModelForm):
eth0_ip=forms.GenericIPAddressField(protocol='IPv4',
widget=forms.TextInput(
attrs={'placeholder': 'xxx.xxx.xxx.xxx'}),
max_length=IPv4_addr_chars,
label=IPv4_addr_html_label,
help_text='required: i.e. 192.168.111.12 ',
required=True
# ,error_messages={'required': 'Please enter IPv4 address, i.e. 192.168.111.12'}
)
config_type = forms.ChoiceField(choices=config_types, widget=forms.RadioSelect())
#,initial='MANUAL')
and in model:
class netInfo(models.Model):
eth0_ip = models.CharField(max_length = IPv4_addr_chars, blank=True, null=False, default=get_eth0_ip_stdout)
config_type = models.CharField(max_length=6, blank=False, null=False, default="DHCP")
W/o using initial value 'DHCP' or 'MANUAL' in sample above the choice starts unselected. Also note that initial could be set in form class (commented above).
So, exactly to your questions:
1> Do I need to define choices too?
Yes, choices should be defined in model.
2> and have the initial value be one of them?
Yes, initial values for choices must match your choices definition for form and model.
At least that's so in django 2.0 .
As about question 1) - I can't claim there is no ability to init choices other way, but for my sample answer for question 2) is exactly that - non-matching values ignored (didn't raise exception).

Multiple Form with Single Submit Button

I'm currently working with django project. I had to filter the data store on the database based on the user input on form (at template) as looked below.
On form user either enter value or leave it blank. So what I have to do is first find the (valid) user input and then fire appropriate query to display data as user input in the form. So final result should be displayed on table at template.
As I'm new to django, how should I have to pass the data and fire query to represent data at multiple field. As help or link related to these type problem are expected. ( I just able to filter from the database with only one form and had no concept to solve this.)
Model of my temp project is as below.
class exReporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
gender = models.CharField(max_length=1)
age = models.IntegerField()
label = models.IntegerField()
There are a number of approaches you can take, but here is one solution you can use that involves chaining together the appropriate filters based on the form's posted data:
*Note: To conform to Python's naming convention, rename exReporter class to ExReporter.
# views.py
def process_ex_reporter_form(request):
if request.method == "POST":
# ExReporterForm implementation details not included.
ex_reporter_form = ExReporterForm(request.POST)
if ex_reporter_form.is_valid():
# If form field has no data, cleaned data should be None.
gender = ex_reporter_form.cleaned_data['gender']
age_start = ex_reporter_form.cleaned_data['age_start']
age_end = ex_reporter_form.cleaned_data['age_end']
aggregation_group = ex_reporter_form.cleaned_data['aggregation_group']
aggregation_id = ex_reporter_form.cleaned_data['aggregation_id']
ex_reporters = ExReporter.objects.get_ex_reporters(gender, age_start,
age_end, aggregation_group, aggregation_id)
else:
# Pass back form for correction.
pass
else:
# Pass new form to user.
pass
# models.py
class ExReporterManager(models.Manager):
def get_ex_reporters(self, gender, age_start, age_end, aggregation_group,
aggregation_id):
ex_reporters = super(ExReporterManager, self).get_query_set().all()
# Even though the filters are being applied in separate statements,
# database will only be hit once.
if ex_reporters:
if gender:
ex_reporters = ex_reporters.filter(gender=gender)
if age_start:
ex_reporters = ex_reporters.filter(age__gt=age_start)
if age_end:
ex_reporters = ex_reporters.filter(age__lt=age_end)
# Apply further filter logic for aggregation types supported.
return ex_reporters

Populate dropdown list by another dropdown list in django with formsets

I have as follows, I have a model Producto that one field is a foreign key to another model called Categoria like this:
class Categoria(models.Model):
nombre = models.CharField(max_length=500)
description = models.TextField(blank=True)
imagen = models.ImageField(upload_to="/media/categorias", blank=True)
class Producto(models.Model):
referencia = models.CharField(max_length=30)
nombre = models.CharField(max_length=500)
cantidad = models.IntegerField()
precio_unidad = models.FloatField(blank=True)
cantidad_en_pedido = models.IntegerField(blank=True)
descatalogado = models.BooleanField(blank=True)
proveedor = models.ForeignKey(Proveedor,related_name="proveedor",blank=True,null=True)
categoria = models.ForeignKey(Categoria,related_name="categoria",blank=True,null=True)
imagen = models.ImageField(upload_to="/media/productos", blank=True)
So, when a user wants to make an order I need to make a dropdown list for Categoriaso when the user make a choice, another dropdown list is filter with the list of products based in this category, something like dropdown list for countries and cities in a form registration of the many websites around the web, for this, I made a modelformset_factory for order detail where the insertion of product happens:
PedidoForm = modelform_factory(Pedido, exclude=("producto",),formfield_callback=make_custom_datefield)
DetallePedidoFormSet = modelformset_factory(Detalle_Pedido,exclude=("unidad_precio","pedido",), extra=1 )
And that's the view for get the order form:
def add_pedido(request):
if request.POST:
pedido_form = PedidoForm(request.POST, prefix='pedido')
detalle_pedido_formset = DetallePedidoFormSet(request.POST, prefix='detalle_pedido')
if pedido_form.is_valid() and detalle_pedido_formset.is_valid():
pedido = pedido_form.save()
nuevos_detalles_pedido = detalle_pedido_formset.save(commit=False)
for nuevo_detalle_pedido in nuevos_detalles_pedido:
nuevo_detalle_pedido.unidad_precio = nuevo_detalle_pedido.producto.precio_unidad
nuevo_detalle_pedido.pedido = pedido
nuevo_detalle_pedido.save()
detalle_pedido_formset.save_m2m()
return HttpResponseRedirect("/ventas/pedidos")
#else:
# form_errors = form.errors
# return render_to_response("ventas/form.html", {'form_errors':form_errors,'form':form},
# context_instance=RequestContext(request))
else:
pedido_form = PedidoForm(prefix='pedido')
detalle_pedido_formset = DetallePedidoFormSet(queryset=Detalle_Pedido.objects.none(),prefix='detalle_pedido') # or give a different initial queryset if you want some preselected choice
extra_context = {'form_pedido': pedido_form, 'detalle_pedido_formset': detalle_pedido_formset}
return render_to_response("ventas/form_pedido.html", extra_context,
context_instance=RequestContext(request))
How could define this in my formsets, many sites suggest of doing a ModelChoiceFieldbut I don't know how to define for a formset, any ideas?
Regards!
I had a similar problem related to populating drop down menus in a formset based on a user selection (which could be multiple rows in a table). What worked for me was to modify the base_fields in the formset before I put the selected rows in the formset like so:
formset = modelformset_factory(mymodel)
formset.form.base_fields['my_parameter'] = forms.ChoiceField(choices=getMyParamChoices())
finalformset = formset(queryset=model.objects.filter(id__in=request.POST.getlist('selection')
'selection' is the list of selected rows from the previous page.
getMyParamChoices() is a function that queries a model to get the list of pulldown choices like so:
def getMyParamChoices():
'''Go get the list of names for the drop down list.'''
all = anothermodel.objects.all()
params = []
for item in all:
new1 = (item.name,item.name)
params.append(new1)
return(tuple(params))
ChoiceField requires a tuple in order to work properly and name is the value I want in the drop down.
I hope this helps. If you want the pull-down to dynamically change on the client side, then you'll need to write some JavaScript to populate the drop down menus.

Django: Deal Wizard and Auto ID

Say I have field named address_line_1 at form, once I render this it is generated as such:
<input id="id_1-address_line_1" type="text" name="1-address_line_1">
And I use this form at different pages however it doesn't have a consistency, one is generated as id_1-address_line_1 while some other same form at another view as id_1-address_line_1 thus it hurty my javascript side. How can I drop the id_X part so that the rendered id has the exact same name as the field name address_line_1
FormClass(prefix="prefix_to_display")
You can get rid of id_ by using the auto_id parameter. In your view class:
def get_form_kwargs(self, step=None):
kwargs = super().get_form_kwargs(step)
kwargs['auto_id'] = True
return kwargs
In order to get rid of the X- you'll have to render the fields manually. This can be done with custom templates, or in the field definitions:
address_line_1 = forms.CharField(
widget=forms.TextInput(attrs={'id': 'address_line_1'})
)