Is there any easy way to change the instance of a Django model form after it's been initialised?
For example the following would pre-populate the form in a template with the contents currently in the db for the object with an id of 1:
form = exampleModelForm(instance = Model.objects.get(pk=1)
This will also save the relevant object when save() is called rather than create a new one.
Where this will create a new object and not pre-populate the form in the template:
form = exampleModelForm()
As I'm returning a blank form from a different method, I would then like to assign an instance to it after it's been created and amend the object so that it can be saved and the template is pre-populate with the values that exist in the db. I want something like this but what I've tried doesn't seem to work:
form = methodThatGetsForm(somearg)
form.instance = ExampleModel.objects.get(pk = getId(somearg))
Is there a simple function that I'm missing here?
I have NOT tested this, but I wonder if you can reinitialize a new form with the returned form data and the instance as the new object.
form = methodThatGetsForm(somearg)
new_form = ExampleModelForm(form.cleaned_data, instance=ExampleModel.objects.get(pk=getID(somearg)))
new_form.save()
If not, there should be a way to get the data as a dictionary of key/value pairs for the fields from the form returned, using it's ._meta data. I think if you send that dictionary to the form init it will assign those values to the instance object, just like sending it request.POST.
Related
I am trying to dynamically acquire my Django Models using apps.get_model(), and then call a method from said Model to properly save the data I am passing it.
temp_model = apps.get_model(app_label='app', model_name=model)()
temp_model.save_data(data)
So far, I am able to access the Model's that I am working with, as well as the method within each Object. What I am unsure of is how to properly save the data within the Object. I have been attempting to use self._meta.get_fields() to iterate over each field and set the field equal to the data I am passing it, but this is where I am getting caught up.
Here is how I am accessing a list of the Model's fields. This is working as expected.
def save_data(self, data):
fields = [field for field in self._meta.get_fields() if field.name not in ['id', ]]
What I am unsure of is how I can then set the fields data to the appropriate piece of data that I want to pass it, and then save the Object.
What is the difference between initial and instance in django formset?
When to use which?
What should I use to show the prepopulated data in an invalid form in the following case:
formset= FormSet(initial=[{'a':list.b} for list in listslist])
if request.method =='post':
formset = FormSet(request.post, ---instance/initial? ---)
initial is to set defaults for new forms.
instances is to set models instances you use as initial models, which will be populated with entered data. You can use this attribute to edit your model instances.
please explain the following
documentation is an example of saving the form in the database:
>>> from myapp.models import Article
>>> from myapp.forms import ArticleForm
#1
# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
#2
# Create a form to edit an existing Article, but use
# POST data to populate the form.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()
here in the first case there is add a new record to the database
in the second case is to update the existing record in the database
in both cases transmitted to POST dictionary that was added or updated. but the latter is transmitted dictionary 'a' through a keyword argument instance (but is used to update the record 'a', and not POST)
question. why in the second case is transferred dictionary POST?
In both cases you actually pass the request.POST dictionary as a single argument to the form's __init__ method. That way the form can differentiate the actual post data and other arguments. The request.POST dictionary is in its completeness saved in the data attribute. Later on, in the is_valid method, the keys and values in the dictionary are checked against the form's fields and used to validate the form and populate the cleaned_data attribute.
I have a very complicated form and I choose to not use ModelForm since I needed flexibility and control over the fields. Since I am not using ModelForm, I can't simply do something like instance=order, where order = Order.objects.get(pk=1).
Currently I am pre-populating every field with initial in the forms.py as oppose to the views.py like this
self.fields['work_type'] = forms.ChoiceField(choices=Order.WORK_TYPE_CHOICES, initial=order.work_type)
But I was wondering if I could pass the entire order object to a form or do I have to declare initial to every field?
Is there a way to do something like
order_form = OrderEditForm(data=request.POST, initial=order)
in views.py?
I have a very complicated form and I choose to not use ModelForm since
I needed flexibility and control over the fields
Everything that you can do using a Form, you can do in a ModelForm such as adding new fields or over-riding attributes on the fields etc.
But I was wondering if I could pass the entire order object to a form
or do I have to declare initial to every field?
You can pass the order object into the form but you will still have to populate each field individually either in the forms or in the view function.
So in your view you would do something like this:
intial = {'order_number': order.number, 'order_id': order.id}
form = OrderForm(initial=initial)
The easiest way to prepopulate data to a form is passing a dictionary as first argument to de form constructor.
order_form = OrderEditForm(order.__dict__())
where __dict__() is a method that passes "order" object attributes to a dictionary with each attribute's name as a key and their content as value.
An example of how to "invent" such a method could be something like:
order_initial = Order.objects.filter(pk=order.pk).values()[0]
and then construct the form with:
order_form = OrderEditForm(order_initial)
Look at this example (how they populate values at "post" time):
For future reference to other people:
I have since found out after reading SO's comments and answers that it's better to use ModelForm even if you end up explicitly defining every field manually (using something like self.fields['foo'] = forms.CharField()).
In any case, if you are trying to pass a dictionary of current values in a form then the best (built-in) way to convert a model to a dictionary is actually using model_to_dict:
from django.forms.models import model_to_dict
order = Order.objects.get(pk=1)
dictionary = model_to_dict(order)
form = OrderEditForm(dictionary)
I got the solution from this blog. I hope this will be helpful for someone.
Basically I have a model with a ManyToMany field, and then a modelform derived from that model where that field is rendered as a "multiple choice" selectbox. In my template I'm having that field omitted, electing instead to prepare the values for that field in the view, then pass those prepared values into request.POST (actually a copy of request.POST because request.POST is immutable), then feeding request.POST to the form and then carry on as normal. I can't figure out how to do this, because request.POST isn't just a simple python dictionary, but instead a QueryDict, which behaves a little differently.
The field I need to populate is called "not_bases". When I create the widget using the form, it works perfectly well internally, but just not to my liking UI-wise. When I inspect the django-form submitted POST value via django's handy debug error window, the working QueryDict looks like this:
<QueryDict: {u'not_bases': [u'005', u'00AR', u'00F', u'00FD'], [...] }>
It appears the value for "not_bases" is a list, but it's not simply a list. I can't just .append() to it because it won't work. I dug around the documentation and found .update(), which appears to work, but doesn't. Here is my code:
newPOST = request.POST.copy()
for base in bases:
newPOST.update({"not_bases": base.identifier})
and here is the output:
<QueryDict: {u'not_bases': [u'KMER', u'KYIP'], u'reference': [u''], [...] }>
But when I feed that QueryDict to the form, I get an form validation error that says "not_bases: Enter a list of values.". Its obvious that the list-looking things coming from the str() representation of the QueryDict are not the same in the two cases above, even though they look exactly the same
So how do I do this?
It's really not clear what you're trying to do here, but I doubt that hacking the QueryDict is the right way to achieve it.
If you are trying to customise the display of the not_bases field, you can simply override the definition in your modelform declaration:
class MyModelForm(forms.ModelForm):
not_bases = forms.ChoiceField(choices=[(base, base) for base in bases])
class Meta:
model = MyModel
Or, if you simply want to avoid showing it on the form, you can exclude it from the form and set the value after validation.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = ['not_bases']
....
if request.POST:
if form.is_valid():
instance = form.save(commit=False)
instance.not_bases = bases
instance.save()
Does either of these do what you want?