django formset - not able to update entries - django

I want to update a formset that can have different entries. I will able to present the formset pre populated with the correct data, however I'm doing something wrong since it does not update but creates a new instance..
I'm seen inlineformset_factory however since I'm passing more than one value to the formset I was not able to work with it..
If anyone has any pointer I will truly appreciate it!
views.py
epis = Contact.objects.filter(episode=int(value))
ContactSet = formset_factory(Contact1Form, extra=len(epis), max_num=len(epis))
if request.method =='POST':
formset = ContactSet(request.POST)
if formset.is_valid():
for form in formset.forms:
age = form.cleaned_data['age']
bcg = form.cleaned_data['bcg_scar']
radio = form.cleaned_data['radiology']
profile = form.save(commit=False)
for i in epis:
profile.contact = i
fields = {'age': age, 'bcg_scar': bcg, 'radiology': radio}
for key, value in fields.items():
if value == u'':
setattr(profile, key, None)
else:
setattr(profile, key, value)
profile.save()
return render_to_response('success.html', {'location': location})
else:
dic = []
for c in epis:
aux = {}
for f in c._meta.fields:
if f.name not in ['contact_id', 'episode']:
aux[f.name] = getattr(c, f.name)
dic.append(aux)
formset = ContactSet(initial=dic)
return render_to_response('form.html',
{ 'msg': msg,
'location': location,
'formset': formset,
'word': word })
forms.py
class ContactForm(forms.ModelForm):
affinity = forms.ModelChoiceField(queryset=Affinity.objects.all(),
label=ugettext("Affinity"))
age = forms.IntegerField(label=ugettext("Age when diagnosed"),
required=False)
MAYBECHOICES = (
('', '---------'),
(ugettext('Yes'), ugettext('Yes')),
(ugettext('No'), ugettext('No')))
bcg_scar = forms.ChoiceField(choices=MAYBECHOICES, label=ugettext(
"BCG scar"), required=False)
radiology = forms.ModelChoiceField(queryset=Radiology.objects.all(),
label=ugettext("Radiology"),required=False)
class Meta:
model = Contact
Any pointers would be of great help!
EDIT
After some suggestions from Catherine
formset = ContactSet(request.POST, queryset=epis)
which gave me this error:
__init__() got an unexpected keyword argument 'queryset'
I try changing
from django.forms.models import modelformset_factory
ContactSet = modelformset_factory(Contact1Form, extra=len(epis), max_num=len(epis))
and this error appeared:
'ModelFormOptions' object has no attribute 'many_to_many'
and then saw that to solve this error I will need to use the name of the model instead.
ContactSet = modelformset_factory(Contact, extra=len(epis), max_num=len(epis))
and I get a MultiValueDictKeyError

You just forget to add instance in the formset,
if request.method =='POST':
formset = ContactSet(request.POST, queryset=epis)
if formset.is_valid():

MyFormSet = modelformset_factory(ModelName, form=MyForm)
qs = ModelName.objects.filter(user=request.user)
formset = MyFormSet(queryset=qs)

Related

Django saving nested formsets that are related to each other column cannot be null error

There are two nested formsets and they are related to each other. When I increase the extra field in the second formset, I get the error column cannot be null. I have no problem saving both forms as one.
Here is my error :
The error
Here is my forms :
class UserTaskForm(forms.ModelForm):
class Meta:
model = UserTask
fields = ['user_id','task_types_id','store_house_id','description']
class TaskSourcesForm(forms.ModelForm):
class Meta:
model = TaskSources
fields = ['product_id', 'product_amount']
TaskSourcesFormSet = modelformset_factory(
TaskSources,
fields=('product_id', 'product_amount',),
extra=2,
)
UserTaskFormFormSet = modelformset_factory(
UserTask,
fields=('user_id','task_types_id','store_house_id','description',),
extra=1,
)
here is my views :
#login_required(login_url="login")
def addUserTask(request):
user_task_form = UserTaskFormFormSet(queryset=UserTask.objects.none(),initial=[{'user_id': request.user}])
formset = TaskSourcesFormSet(queryset=TaskSources.objects.none())
if request.method == 'POST':
user_task_form = UserTaskFormFormSet(request.POST)
formset = TaskSourcesFormSet(request.POST)
if user_task_form.is_valid():
for form in user_task_form:
user_task = form.save(commit=False)
user_task.author = request.user
user_task.save()
if formset.is_valid():
for form_data in formset:
task_sources = form_data.save(commit=False)
task_sources.user_task_id = UserTask(id = user_task.id)
task_sources.save()
messages.success(request,"Task added successfully!")
return redirect(".")
context = {
"user_task_form" : user_task_form,
"formset" : formset,
}
return render(request,"user/addtask.html",context)
How to save two model formsets together(relates to each other) in one view? what is the wrong part when i do it?
I suspect the problem comes from empty fields in your formsets forms. You can avoid empty forms with:
for form in user_task_form:
if form.has_changed():
user_task = form.save(commit=False)

Django - ModelForm - initial value

I'm working with Modelforms and would like to set the initial value of the "feeder" field. I get the following Type Error: "invalid literal for int() with base 10: 'None'" What might be the problem?
Many thanks all
forms.py:
class CashFlowForm(forms.ModelForm):
class Meta:
model = models.CashFlow
fields = ['type', 'amount', 'description','date']
widgets = {'date': DatePicker()}
views.py:
def create_cashflow(request, fundslug):
funddetail = Fund.objects.get(slug=fundslug)
if request.method == 'POST':
cf = CashFlowForm(request.POST)
cf.feeder = funddetail.feeder
if cf.is_valid():
instance_cf = cf.save()
messages.success(request, 'Cash Flow successfully added!')
return redirect('funds:create_cashflow', fundslug = fundslug)
else:
cf = CashFlowForm()
return render(request, 'funds/create_cashflow.html', {'cf': cf})
I fink funddetail.feeder return None or You can try
cf.cleaned_data['feeder'] = funddetail.feeder
Models don't matter unless there's a foreign key involved. For the Type Error, it's mostly to do with the value your model fields are getting from the form.
For assigning value after form submission, do something like
if request.method == 'POST':
cf = CashFlowForm(request.POST)
cf.save(commit=False)
cf.feeder = funddetail.feeder
cf.save()

Pre-populating Model Form with object data - Django

I have tried various options for this but no luck so far. I am trying to get instance data to be pre-populated into my ModelField. Here is what I have:
forms.py
class edit_project_info(ModelForm):
project_name = forms.CharField(max_length=150)
class Meta:
model = Project
exclude = ['project_type', 'created_date', 'start_date', 'end_date', 'pm_scope', 'dev_scope', 'design_scope', 'testing_scope' ]
View.py
def edit_project (request, offset):
this_project = Project.objects.get(pk=offset)
data = {'project_name' : 'abc'}
if request.method == 'POST':
form = edit_project_info(request.POST, instance=this_project, initial=data)
if form.is_valid():
form.save()
return HttpResponseRedirect('/project_profile/%s/' % offset)
else:
form = edit_project_info()
All I get is an empty field. I can add the initial value to forms.py, but then it is static rather than populated based on the form instance. What I have done here with creating a dict and then passing it to initial in the form instance does not seem to do anything. I'm sure I am missing something basic. Any help would be great! Thanks ahead of time.
Two last lines recreate your form variable. Just remove else: form = edit_project_info():
def edit_project (request, offset):
this_project = Project.objects.get(pk=offset)
data = {'project_name' : 'abc'}
form = edit_project_info(request.POST, instance=this_project, initial=data)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponseRedirect('/project_profile/%s/' % offset)
# else:
# form = edit_project_info()
# ...

django prepopulate modelform - nothing happens

This must be a very simple thing however I can not seem to get through it..
I trying to build a form where the user can update a ModelForm. First he inserts a user id and afterwards I want to show him the form pre-populate with the original data so he can change only the fields that he wants.
After some the help of my friend google, stackoverflow and the django documentation, I've come to this:
views.py
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(instance=user)
return render_to_response('template.html',{'form':form})
forms.py
class TableForm(forms.ModelForm):
pres_clinic = forms.ModelChoiceField(queryset=PresClinic.objects.all(),
widget=SelectWithPop(), label=ugettext("Clinic presentation"),
required=False)
MAYBECHOICES = (
('', '---------'),
(ugettext('Yes'), ugettext('Yes')),
(ugettext('No'), ugettext('No')))
bcg_scar = forms.ChoiceField(choices=MAYBECHOICES, label=ugettext(
"BCG scar"), required=False)
mantoux_register = forms.ChoiceField(choices=MAYBECHOICES,
label=ugettext("Mantoux register"), required=False)
date_diag = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Diagnosis date"), required=False)
situation = forms.ModelChoiceField(queryset=Situation.objects.all(),
widget=SelectWithPop(), label=ugettext("Patient status"),
required=False)
date_situation = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Date patient status"), required=False)
class Meta:
model = Table
fields = ('pres_clinic', 'bcg_scar', 'mantoux_register',
'date_diag', 'situation', 'date_situation')
def clean(self):
cleaned_data = self.cleaned_data
diag = cleaned_data.get('date_diag')
errors = []
now = datetime.date.today()
if diag is not None and diag != u'':
if diag > now:
errors.append(ugettext('The field "Diagnosis date" should be '
'smaller than the actual date'))
if errors:
raise ValidationError(errors)
return cleaned_data
template:
{{ form }} # presents the empty form and not the data from that user
The version of django is 1.4
Can anyone tell me what is wrong and why I'm not able to see the form populated?
Thank you very much
You need to define a dictionary to be used for the initial data and change from TableForm(instance=user) to TableForm(initial=dict), for example something like:
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
data = {'pres_clinic' : 'value', 'bcg_scar' : 'value', 'mantoux_register' : 'value'}
form = TableForm(initial=data)
return render_to_response('template.html',{'form':form})
I would also put the render to response out of the if statement so if the form isn't valid the page should reload and show any errors.
More information on the django docs here
I hope this helps!
You can try 'model_to_dict'
from django.forms.models import model_to_dict
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(initial=model_to_dict(user))
return render_to_response('template.html',{'form':form})

formset_factory and updating a field to show only filtered items

On my scorecard entry form, i only want the user to select from the shortlisted players for that match. If there was one field, I am succesfully able to rewrite using.
form.fields['player'].queryset = PlayerShortlist.objects.filter(team=userteam, fixture=fixture_id)
but when i apply it on formset_factory, i am unable to get result.
my forms.py
class TossForm(forms.Form):
toss_won_by = forms.BooleanField()
bat_first = forms.BooleanField()
class InningsForm(forms.Form):
player = forms.ModelChoiceField(
PlayerShortlist.objects.all()
)
status = forms.ChoiceField(choices=OUT_CHOICES, initial='DNB')
score = forms.IntegerField(initial=0)
balls_faced = forms.IntegerField(initial=0)
my views.py
#login_required
def scorecard(request, team_id, fixture_id):
template = get_template('cricket/scorecard.html')
tossform = TossForm()
#inningform = InningsForm()
InningsForms = formset_factory(InningsForm, extra=11)
inningsforms = InningsForm()
inningsforms.fields['player'].queryset = PlayerShortlist.objects.filter(team=Team.objects.get(id=1), fixture=fixture_id)
page_vars = Context({
'loggedinuser': request.user,
'tossform': tossform,
'inningsforms': inningsforms,
})
crsfcontext = RequestContext(request, page_vars)
output = template.render(crsfcontext)
return HttpResponse(output)
it gives me errors.
'InningsFormFormSet' object has no attribute 'fields'
thanks
//yousuf
okey, i looked around, and it seems formfield_callback can be used for what i intend it for but when i use it lin my views.py like
def update_field(field, **kwargs):
if field.name == 'players':
field.queryset = PlayerShortlist.objects.filter(team=Team.objects.get(id=team_id), fixture=fixture_id)
InningsFormset = formset_factory(InningsForm, extra=11, formfield_callback)
it gives me
formset_factory() got an unexpected keyword argument 'formfield_callback'
Remember: a formset wraps around a list of forms. So this:
inningsforms.fields['player'].queryset = PlayerShortlist.objects.filter(team=Team.objects.get(id=1), fixture=fixture_id)
Should rather be:
qs = PlayerShortlist.objects.filter(team=Team.objects.get(id=1), fixture=fixture_id)
# force execution of the queryset once and for all
list(qs)
for form in inningsforms.forms:
form.fields['player'].queryset = qs
Also, formfield_callback is an argument of modelformset_factory (and modelform_factory), not of formset_factory. See how it is used:
def modelformset_factory(model, form=ModelForm, formfield_callback=None,
formset=BaseModelFormSet,
extra=1, can_delete=False, can_order=False,
max_num=None, fields=None, exclude=None):
"""
Returns a FormSet class for the given Django model class.
"""
form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
formfield_callback=formfield_callback)
FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
can_order=can_order, can_delete=can_delete)
FormSet.model = model
return FormSet
See, formfield_callback is proxied to modelform_factory by modelformset_factory.