I need to know why may I need to use instance into ModelForm I read about it in Django document what I understand that it can replace with save() method somehow if that is correct why I have to use it if not how can I use it and why?
Suppose you have a record in your models whose pk=1. So first you fetch the instance, and then you can create a form in your views by passing the instance argument. So if changes are made to some fields, the same record will be updated.
In your views -
a = ModelName.objects.get(pk=1) //Fetching the record you want to update
form = ModelFormName((request.POST, instance=a) or None)
if form.is_valid():
record = form.save(commit=False)
//Modify the records fields which you get from form
record.save()
// if not valid send it to template via context
Use this form in your templates as you would do in a normal form.
Related
I have a Model with 5 fields. I create a ModelForm on top of that model, now I intialize the form with request data containing 4 fields.
The reason of 4 fields in request data is the checkbox on frontend that isn't passed using jquery FormData when unchecked.
Now the problem is, I want to set a default value of the 5th field at the time of form initialization if checkbox is not passed in request data.
What would be the best thing to do, set default value in ModelForm or Form or use default value from Model or I can set the value of a specific field.
Sugesstions are welcome. TIA.
You can mess around with request.POST before binding it to the form. If you are using CBV FormView you can subclass get_form_kwargs. Something like
# UNTESTED CODE
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.request.method in ('POST', 'PUT'):
if 'foo' not in kwargs['data']:
#this starts as request.POST which is an immutable QueryDict
data = kwargs['data'].copy() # mutable copy
data['foo'] = 'whatever' #supply the missing default value
kwargs['data'] = data
return kwargs
Consult the Django documentation w.r.t. QueryDict. They are tricky beasts that are directory-like but the differences can be enough to catch you out. It's easy to create one at the shell prompt and play with it to make sure you get this right.
Previsouly, I used forms.ModelForm to create a Django form and in views.py used:
p_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.profile)
This way, if the form was not valid when submitted, it would repopulate the information the user entered previously. This saved a user from having to enter the information again.
I have since changed to forms.Form because I can't figure out how to customize Crispy Forms using forms.ModelForm, but now if I call instance=request.user.profile, I get an error.
What can I do to repopulate the information the user previously placed in the form so they do not have to do it again?
You can populate the fields of a form with the initial=… parameter [Django-doc], this then contains a dictionary that maps the fields to the corresponding value.
So if your form for example is defined as:
class ProfileUpdateForm(forms.Form):
name = forms.CharField()
age = forms.IntegerField()
you can construct a form with:
ProfileUpdateForm(initial={'name': 'Jason G', 'age': 25})
A ModelForm basically does the same, except that here it obtains the initial values form the instance=… parameter, and thus obtains attributes from that object and passes these to the corresponding form fields.
That being said, normally crispy forms work quite well with ModelForms, so perhaps it is better to take a look what the problem is with your ModelForms and try to fix this over "circumventing" the problem, but making it harder to work with your forms.
Help needed with pre-populating Django forms: I have a form that updates a UserProfile model, when the form is loaded I want it pre-populated with the existing UserProfile data. Simple enough, the instance can be passed to the form. However, it seems that fields with choices (which come out as select drop-down elements in HTML) are not pre-populated with the instance data and instead default to '-----------'.
I've tried manually setting the initial value for a specific form (e.g. country) but it doesn't pull through to the HTML.
form = UserProfileForm(instance=user_profile)
form.fields['country'].initial = 'GBR'
I'm sure I could create a convoluted work around to get the current country selected in the front-end but it feels like it should be possible in Django. I couldn't see any solutions in other questions.
You can dynamically set default for a form field as:
form = UserProfileForm(instance=user_profile, initial={'country': 'GBR'})
If country field should be populated from user_profile data, then you can define form as following (assuming country is a field in UserProfile class)
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
if self.instance:
self.initial['country'] = instance.country
Why what you are doing isn't working?
You are using:
form.fields['country'].initial = 'GBR'
This will not work on for a bounded form. form = UserProfileForm(instance=user_profile) will return a bounded form.
From docs:
The initial argument lets you specify the initial value to use when rendering this Field in an unbound Form.
To specify dynamic initial data, see the Form.initial parameter.
I'm trying to set up a django form consisting solely of a formset. In forms.py I have:
class StudentEnrolmentForm(forms.ModelForm):
school_class = forms.ModelChoiceField(SchoolClass.objects.currently_enrolling())
class Meta:
model = StudentApplication
fields = []
StudentEnrolmentFormSet = modelformset_factory(StudentApplication, StudentEnrolmentForm, extra=0)
but I'm unclear how to incorporate the FormSet into a CBV (In this case I've chosen a FormView). In this case I'm basically displaying a table of students, and allowing the operator to assign each student to a class. I only want a single 'submit' button at the end of the page.
If you will take a look on sources of Django views and check how FormView is working, you find that it just overrides default get and post methods of base View class and adds some additional methods for the form handling.
So you can:
try to assign your formset to the form_class field of your view and
play around. Probably you will have to override some additional
methods;
take a look on https://github.com/AndrewIngram/django-extra-views;
if options #1 and #2 causes too much pain - use default View
I have refered this documentation page for save() method
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
But in my view I have the following code
def saveEvent(request):
eventForm = EventForm(request.POST)
if eventForm.is_valid():
event=eventForm.save(commit=False)
requestor=None
if(event.is_hp_requestor):
#Save and get requestor
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestorHPEmployeeForm = HPEmployeeForm(request.POST, prefix = 'hp_requestor')
requestor=saveHPEmployeeHelper(requestorHPEmployeeForm, requestorHPPersonForm).person
else:
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestor=get_object_or_404(Person, pk=requestorHPPersonForm.data[requestorHPPersonForm.prefix+'-'+'email'])
if (requestor is not None) and eventForm.is_valid():
event.requestor_new=requestor
event.save()
if request.POST['opportunities']:
for str_sfid in request.POST['opportunities'].split(','):
sfid = int(str_sfid)
opportunity_object, dummy = Opportunity.objects.get_or_create(sfdc_id=sfid)
event.opportunities.add(opportunity_object)
event.save()
return HttpResponseRedirect(reverse('dashboard'))
else:
errors = eventForm.errors
return HttpResponse(json.dumps(errors), status=500, mimetype='application/json')
In my view I do not invoke the save_m2m() method, but still it save many2many field data.
How is it works, if this is working then why we need the save_m2m() method?
The docs you linked to explain this:
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data – including many-to-many data – is saved without the need for any additional method calls.
Also, it looks like event is itself a model instance rather than a form. save_m2m is required for forms, not model instances.
To paraphrase the explanation in the docs: a form's save method, if called with commit=True (the default) does two things - it creates a new model instance using the form's cleaned data, and it writes that model instance to the database. Then, if there are any many-to-many relationships, it writes those to the database as well. It does that after writing the instance because you can't write a many-to-many relationship until the instance has a primary key, which is auto-generated when you write it to the database.
If you call the form's save method with commit=False, it creates the new model instance but it does not write it to the database. Thus, it has no primary key yet and the many-to-many information can't be saved either. After you save the model instance and therefore generate a primary key for it, the many-to-many information is still stored only in the form object. So you need to notify the form object that it's now OK to save the many-to-many information, by calling save_m2m.
edit Since you've added more of your code I can see more clearly what you're asking. The above code will not save many-to-many relationships that are set in your EventForm instance. Is that what your loop to set opportunities is doing?