I have an object (myModel) which i want to create according to a form(myModelForm), I also want that the object would be related to a requiered ForeignKey object (Group) which i want to decide by myself.(i.e, don't want it to be in the form.
So if I try to use form.save() i get an error. is there a way i can add Group ForeignKey (in view) before i use save()?
My code looks something like this:
class myModel(models.Model):
myGroup = ForeignKey(Group)
normal_field1 = TextField()
...
normal_field2 = TextField()
class myModelForm(ModelForm):
class Meta:
model = myModel
fields = [normal_field1,noraml_field2]
muchas gracias
Use commit=False to create the item without persisting it to the database.
if form.is_valid():
obj = form.save(commit=False)
obj.myGroup= whatever
obj.save()
Related
I am trying to solve one issue about saving data in db.
This is an example how I think of it:
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
fieldX = models.SomeFieldType()
#property:
def foo(self):
return self._foo
#foo.setter
def foo(self, var):
self._foo=var
class MyModelForm(models.Modelform):
class Meta:
model = models.MyModel
fields = '__all__'
The thing is I have dict that I am passing to this form (so I am not using view or any provided interaction with user directly. In dict I have some fields and what I want to do is one field that is passed to use it as model property but I do not want it to be saved in db.
So I tried something like:
form = MyModelForm(data_dict)
if form.is_valid():
form.foo = data_dict['data_for_property_not_db']
form.save()
Form does not know that my model has this property.
So basiclly what I want is to write some parts of my data_dict normaly to form and db as always ->works fine
and then I want some data_info pass to that property and use it somewhere in save() as needed without saving it to db itself.
Can you help me with this?
So to make the above possible I have found out that I have to have ManytoMany Field that is not a problem.
That field is in the form as follows:
class Form(forms.ModelForm):
class Meta:
model = MyModel
fields = ['notes', 'scan']
widgets = {
'scan': forms.CheckboxSelectMultiple(),
}
In the view I have this then:
form = Form(request.POST)
if from.is_valid():
inst = from.save(commit=False)
inst.something = something
inst.save()
Now what do I do, to save the test or scan from the form?
I tried :
inst.test.add(form.cleaned_data['test'])
But that doesn't work for test or scan.
The Model looks like this:
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
notes = models.TextField(default='')
scan = models.ManyToManyField(Scan)
....
Please help I wasn't able find anything in the Internet about this
Thanks!
The documentation of the Form's save method tells it all: If you have a ModelForm that contains the model's ManyToManyField like this:
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['__all__'] # or fields = ['scans'] assuming scans is the M2M field in MyModel
Then you have two ways to save the relationships:
Directly, using form.save()
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.
Or indirectly because you want to manipulate the instance before saving:
if form.is_valid():
instance = form.save(commit=False)
instance.some_field = some_value
instance.save()
form.save_m2m() # this saves the relationships
I have a model that looks like this:
models.py
class BHA_List(models.Model):
well = models.ForeignKey(WellInfo, 'CASCADE', related_name='bha_list')
bha_number = models.CharField(max_length=100)
class BHA_Drill_Bit(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_drill_bit')
bit_type = models.CharField(max_length=111)
class BHA_overall(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_overall')
drill_str_name = models.CharField(max_length=111)
class BHA_Motor(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_drill_bit')
motor_type = models.CharField(max_length=111)
BHA_List is a parent model, and the rest are child models related by ForeignKey. The screenshot is the page I want to create
So, I want to generate a base page using one of the instances in model = BHA_List. In this page, I want to edit model instances that are related to BHA_List by ForeignKey relationship.
I currently have a view that looks like this, but its wrong:
class BHA_UpdateView(UpdateView):
model = BHA_List
pk_url_kwarg = 'pk_alt'
form_class = BHA_overall_Form
By setting model = BHA_List, I was able to get one of the instances in BHA_List, and generate url from it. Right now my views correctly return one of the instances in BHA_List: BHA 1
I attempted to edit child models by setting form_class = BHA_overall_Form. But this doesn't do anything, though it displayed form fields on the user side. After editing and clicking Submit button, the changes are not saved in DB. Someone pointed out that this is because my model in UpdateView and form does not match, as I set model = BHA_List, but form_class = BHA_overall_form.
How can I resolve this issue? Someone else also pointed out using multiple views, but I don't really know how to do it, as I'm very new to Django. Any help will be greatly appreciated. Thanks!
Just so that you know. UpdateView can be used if you want to update a single row in one table. When you set model = BHA_LIST you are saying Django. Hey, Django I want to update this model so render me a form with the fields from this table. You can do this by just setting fields attr on the model or use a form like you did which will customize which fields are shown. Now the good thing about allowing to set our own form is. Though we create a modelForm we can also add extra fields inside it. Now your BHAOverallForm should look like this to accommodate all the fields you need.
forms.py
class BHAOverallForm(forms.ModelForm):
well = models.ForeignKey(WellInfo, 'CASCADE', related_name='bha_list')
bha_number = models.CharField(max_length=100)
bit_type = models.CharField(max_length=111
drill_str_name = models.CharField(max_length=111)
motor_type = models.CharField(max_length=111)
class Meta:
model = BHAList
you can use this form inside your form like you do now. You can also add clean_field to add validations. Now coming to the update part. your views should look like this
views.py
class BHAUpdateView(UpdateView):
model = BHAList
form_class = BHAOverallForm
def form_valid(self, form):
super(BHAUpdateView, self).form_valid(form) # save BHAList to the DB
bha_list = form.instance
bha_drill_bit = bha_list.bhadrillbit_set.first() # assuming you have only one drill_bit per list, if you need more modify your question accordingly.
bha_drill_bit.bit_type = form.cleaned_data.get("bit_type)
bha_drill_bit.save()
# you can do the same for other models as well.
I have different models in my app, the main model having multiple instances of some other models.
models.py:
class Person(models.Model):
...
class Pet(models.Model):
owner = models.ForeignKey(Person)
...
forms.py:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
PetFormSet = inlineformset_factory(Person, Pet, extra = 1)
views.py:
def add_template(request):
person_form = PersonForm(prefix = 'person_form')
pet_form = PetFormSet(instance = Person(), prefix = 'pet_form')
... # check is_valid(), render when no POST data is present, etc.
The point is the addition works perfectly, storing each instance in the corresponding database table, etc. I use jquery.formset-1.2.js to manage the dynamical addition-deletion of forms in the "add.html".
But I later want to edit the stored info through a view, i.e., load the data from the object I pass in the request, and render the formsets with the data obtained from the database (if there are 3 pets related to the person being editted, display 3 form instances of "Pet" with their value displayed).
I would like to also add new Pets and remove existing ones, as well as changing existing field values.
I have tried with querysets in the FormSet creation, but it doesn't display anything.
Any idea how to ease this issue? Maybe using an app for an easier formset management?
Thank you
I'm not sure if I understand your problem correctly. If you want to display all Pets that belong to the Person:
def show_pets(request, person_id=None):
person = get_object_or_404(Person.objects.select_related(), id=person_id)
if request.method == 'POST':
person_form = PersonForm(request.POST, instance=person)
pet_formset = PetFormSet(request.POST, instance=person)
# Rest of your code here
else:
person_form = PersonForm(instance=person)
pet_formset = PetFormSet(instance=person)
return render_to_response('your_template.html', {'person_form': person_form,
'pet_formset': pet_formset)})
Then you just need to render both forms in your template and add add and delete functionality
I have a complex django object, which has properties of other class types. This gets like this:
class Order:
contractor - type Person
some other fields....
In my form I'd like to be able to either choose existing Person object from the dropdown or add a new one with a form. I've managed to create forms and appropriate workflow, but the problem is with saving the Order itself, I simply can't get the id of a saved Person instance. I'm doing sth like this:
def make_order(request):
if request.method == 'POST':
parameters = copy.copy(request.POST)
contractor_form = ContractorForm(parameters)
if contractor_form.is_valid():
contractor_form.save()
parameters['contractor'] = ???
form = OrderForm(parameters)
if form.is_valid():
form.save()
return HttpResponseRedirect('/orders/')
else:
form = OrderForm()
contractor_form = ContractorForm()
return render_to_response('orders/make_order.html', {'order_form' : form, 'contractor_form' : contractor_form})
So, if POST request reaches this method I first check if ContractorForm have been filled - I assume that if the form is valid, it is meant to be used. If yes, than I save it and would like to assign the saved object's database id to appropriate field for OrderForm to find it.
All my forms are ModelForms.
The questions are:
Are there better ways to do this? (choose from dropdown or add in place) - better or more pythonic ;-)
How can I get saved objects id when using ModelForms?
Edited
My ContractorForm is:
class ContractorForm(ModelForm):
class Meta:
model = Contractor
Nothing fancy.
save() should return the newly created instance.
if contractor_form.is_valid():
instance = contractor_form.save()
parameters['contractor'] = instance
where id would be instance.id, or even better instance.pk.
pk vs. id:
Regardless of whether you define a
primary key field yourself, or let
Django supply one for you, each model
will have a property called pk. It
behaves like a normal attribute on the
model, but is actually an alias for
whichever attribute is the primary key
field for the model. You can read and
set this value, just as you would for
any other attribute, and it will
update the correct field in the model.
Follow-up on comment:
Well it does work by default, so there must be something else wrong.
models.py
class Category(models.Model):
name = models.CharField(max_length=70)
slug = models.SlugField()
forms.py
from django import forms
from models import Category
class MyModelForm(forms.ModelForm):
class Meta:
model = Category
Test in shell:
In [3]: from katalog.forms import MyModelForm
In [4]: data = {'name':'Test', 'slug':'test'}
In [5]: form = MyModelForm(data)
In [6]: instance = form.save()
In [7]: instance
Out[7]: <Category: Test>
In [8]: instance.id
Out[8]: 5L