Django - ModelForm - initial value - django

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()

Related

how to get field value from model

I have a model for registering with some fields.
All fields are models I fill in through the form like this.
def get_name(request):
if request.method == 'POST':
user_code = generate_code(8)
subject = 'code'
message = user_code
phone=request.POST['phone']
form = NameForm(request.POST)
if form.is_valid():
date_use = form.cleaned_data.get("date_visit")
time_use = form.cleaned_data.get("time_visit")
purpose_use = form.cleaned_data.get("purpose")
if Registration.objects.filter(date_visit=date_use,time_visit=time_use,purpose=purpose_use).count()==0:
Registration.objects.create(fio=request.POST['fio'],phone=request.POST['phone'],date_visit=request.POST['date_visit'],time_visit=request.POST['time_visit'],
number_car=request.POST['number_car'],purpose=request.POST['purpose'],
tso=request.POST['tso'])
request.session["phone"] = phone
request.session["code"] = user_code
return HttpResponseRedirect('endreg')
else:
form = NameForm()
return render(request, 'registers/detail.html', {'form': form})
The model also has a field
date_register = models.DateTimeField(verbose_name = 'date register', auto_now_add=True)
how can i write date_register value in request.session["date"] ?
Instead of using Registration.objects.create(...) you can use .save method:
obj = Registration()
obj.fio = form.cleaned_data["fio"]
...
obj.save()
request.session["date"] = str(obj.date_register)
By default django use JSONSerializer and it can't dump datetime objects.
The simplest solution is using PickleSerializer as SESSION_SERIALIZER, but it can cause performance issues (docs: https://docs.djangoproject.com/en/3.0/ref/settings/#std:setting-SESSION_SERIALIZER)
Another way to do it - write you custom json serializer, based on django serializer, but with default function for dumping datetime objects, or simple convert date to string format or timestamp before saving to session.

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})

django formset - not able to update entries

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)

Django form is_valid() fails

I am a real beginner in web development. The following code is failing at the is_valid() check. But I do not understand why: The form should get its data filled from the POST-data or not?
Model:
class Statement(models.Model):
text = models.CharField(max_length=255)
user = models.ForeignKey(User)
time = models.DateField()
views = models.IntegerField()
ModelForm:
class StatementForm(ModelForm):
class Meta:
model = Statement
widgets = {
'time':forms.HiddenInput(),
'user':forms.HiddenInput(),
'views':forms.HiddenInput(),
}
View function:
def new(request):
if request.method == 'POST': # If the form has been submitted...
form = StatementForm(request.POST) # A form bound to the POST data
if form.is_valid():
stmt = form.save()
path = 'stmt/' + stmt.id
return render_to_response(path, {'stmt': stmt})
else:
c = {}
c.update(csrf(request))
loggedin_user = request.user
d = datetime.now()
form = StatementForm(request.POST, initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})
return render_to_response('new_stmt.html', {'form': form, },context_instance=RequestContext(request))
I found similar topics and tried a lot. This is how i think it should work. I really need advice.
All fields of your model are required. So, form.is_valid() will be True, if all fields are filled with correct values and are not blanked.
You have declared fields time, user, views as hidden fields. Are you sure, that you have filled them in your template form?
Also, you may want to auto stamp field time = models.DateField(). Modify your model field like
time = models.DateField(auto_now=True)`.
After this you don't have to fill it by yourself in template form.
Your view must return HttpResponse object in all cases. If your form is not valid, i.e. if form.is_valid() will return False, then no HttpResponse object will be returned by your view. This can be the source of your fail. Add else statement for if form.is_valid():
from django.http import Http404
def new(request):
if request.method == 'POST': # If the form has been submitted...
form = StatementForm(request.POST) # A form bound to the POST data
if form.is_valid():
stmt = form.save()
path = 'stmt/' + stmt.id
return render_to_response(path, {'stmt': stmt})
else:
# Do something in case if form is not valid
raise Http404
else:
# Your code without changes
Change this line:
form = StatementForm(request.POST, initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})
For this:
form = StatementForm(initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})

Why doesn't Django enforce my unique_together constraint as a form.ValidationError instead of throwing an exception?

Edit: While this post is a duplicate of Django's ModelForm unique_together validation, the accepted answer here of removing the 'exclude' from the ModelForm is a much cleaner solution than the accepted answer in the other question.
This is a follow-up to this question.
If I don't explicitly check the unique_together constraint in the clean_title() function, django throws an exception:
IntegrityError at /journal/journal/4
duplicate key value violates unique constraint "journal_journal_owner_id_key"
Request Method: POST
Request URL: http://localhost:8000/journal/journal/4
Exception Type: IntegrityError
Exception Value: duplicate key value violates unique constraint "journal_journal_owner_id_key"
Exception Location: /Library/Python/2.6/site-packages/django/db/backends/util.py in execute, line 19
However I was under the impression that Django would enforce this constraint nicely by raising a ValidationError, not with an exception I need to catch.
Below is my code with an additional clean_title() method I use as a work-around. But I want to know what I'm doing wrong such that django is not enforcing the constraint in the expected manner.
Thanks.
Model code:
class Journal (models.Model):
owner = models.ForeignKey(User, related_name='journals')
title = models.CharField(null=False, max_length=256)
published = models.BooleanField(default=False)
class Meta:
unique_together = ("owner", "title")
def __unicode__(self):
return self.title
Form code:
class JournalForm (ModelForm):
class Meta:
model = models.Journal
exclude = ('owner',)
html_input = forms.CharField(label=u'Journal Content:', widget=TinyMCE(attrs={'cols':'85', 'rows':'40'}, ), )
def clean_title(self):
title = self.cleaned_data['title']
if self.instance.id:
if models.Journal.objects.filter(owner=self.instance.owner, title=title).exclude(id=self.instance.id).count() > 0:
raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
else:
if models.Journal.objects.filter(owner=self.instance.owner, title=title).count() > 0:
raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
return title
View Code:
def journal (request, id=''):
if not request.user.is_active:
return _handle_login(request)
owner = request.user
try:
if request.method == 'GET':
if '' == id:
form = forms.JournalForm(instance=owner)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
journal = models.Journal.objects.get(id=id)
if request.user.id != journal.owner.id:
return http.HttpResponseForbidden('<h1>Access denied</h1>')
data = {
'title' : journal.title,
'html_input' : _journal_fields_to_HTML(journal.id),
'published' : journal.published
}
form = forms.JournalForm(data, instance=journal)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
elif request.method == 'POST':
if LOGIN_FORM_KEY in request.POST:
return _handle_login(request)
else:
if '' == id:
journal = models.Journal()
journal.owner = owner
else:
journal = models.Journal.objects.get(id=id)
form = forms.JournalForm(data=request.POST, instance=journal)
if form.is_valid():
journal.owner = owner
journal.title = form.cleaned_data['title']
journal.published = form.cleaned_data['published']
journal.save()
if _HTML_to_journal_fields(journal, form.cleaned_data['html_input']):
html_memo = "Save successful."
else:
html_memo = "Unable to save Journal."
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'saved':html_memo})
else:
return shortcuts.render_to_response('journal/Journal.html', { 'form':form })
return http.HttpResponseNotAllowed(['GET', 'POST'])
except models.Journal.DoesNotExist:
return http.HttpResponseNotFound('<h1>Requested journal not found</h1>')
UPDATE WORKING CODE:
Thanks to Daniel Roseman.
Model code stays the same as above.
Form code - remove exclude statement and clean_title function:
class JournalForm (ModelForm):
class Meta:
model = models.Journal
html_input = forms.CharField(label=u'Journal Content:', widget=TinyMCE(attrs={'cols':'85', 'rows':'40'},),)
View Code - add custom uniqueness error message:
def journal (request, id=''):
if not request.user.is_active:
return _handle_login(request)
try:
if '' != id:
journal = models.Journal.objects.get(id=id)
if request.user.id != journal.owner.id:
return http.HttpResponseForbidden('<h1>Access denied</h1>')
if request.method == 'GET':
if '' == id:
form = forms.JournalForm()
else:
form = forms.JournalForm(initial={'html_input':_journal_fields_to_HTML(journal.id)},instance=journal)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
elif request.method == 'POST':
if LOGIN_FORM_KEY in request.POST:
return _handle_login(request)
data = request.POST.copy()
data['owner'] = request.user.id
if '' == id:
form = forms.JournalForm(data)
else:
form = forms.JournalForm(data, instance=journal)
if form.is_valid():
journal = form.save()
if _HTML_to_journal_fields(journal, form.cleaned_data['html_input']):
html_memo = "Save successful."
else:
html_memo = "Unable to save Journal."
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'saved':html_memo})
else:
if form.unique_error_message:
err_message = u'You already have a Lab Journal with that title. Please change your title so it is unique.'
else:
err_message = form.errors
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'error_message':err_message})
return http.HttpResponseNotAllowed(['GET', 'POST'])
except models.Journal.DoesNotExist:
return http.HttpResponseNotFound('<h1>Requested journal not found</h1>')
The trouble is that you're specifically excluding one of the fields involved in the unique check, and Django won't run the check in this circumstance - see the _get_unique_checks method in line 722 of django.db.models.base.
Instead of excluding the owner field, I would consider just leaving it out of the template and setting the value explicitly on the data you're passing in on instantiation:
data = request.POST.copy()
data['owner'] = request.user.id
form = JournalForm(data, instance=journal)
Note that you're not really using the power of the modelform here. You don't need to explicitly set the data dictionary on the initial GET - and, in fact, you shouldn't pass a data parameter there, as it triggers validation: if you need to pass in values that are different to the instance's, you should use initial instead. But most of the time, just passing instance is enough.
And, on POST, again you don't need to set the values explicitly: you can just do:
journal = form.save()
which will update the instance correctly and return it.
I think the philosophy here is that unique_together is an ORM concept, not a property of a form. If you want to enforce unique_together for a particular form, you can write your own clean method, which is easy, straightforward, and very flexible:
http://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
This will replace the clean_title method you have written.