I have two models
class Model_1(models.Model):
foreign_key_field = models.ForeignKey(Model_2)
class Model_2(models.Model):
number = models.IntegerField()
I need a ModelForm to edit a Model_2 object. In that form I want a list of all Model_1 objects and the option to checkbox those Model_1 fields that should use the specific Model_2 object as ForeignKey.
Actually, it should work something like a ManyToMany field, but in a ManyToOne relationship.
Maybe the ModelForm could look something like this:
class SetForeignKeyForm(ModelForm):
is_linked = BooleanField(required=False)
class Meta:
model = ModelName
fields = ()
def clean_is_linked(self):
if self.cleaned_data['is_linked']:
self.fields['foreign_key_field'] = self.object
and the view:
class Model2UpdateView(ModelFormSetView):
model = Model_2
form_class = SetForeignKeyForm
def get_queryset(self):
return Model_2.objects.all()
I don't know how to get the Model_2 object in my custom ModelForm, so I don't know how to save whether the Model_1 object is linked to the specific Model_2 object or not.
I will end up with a output which looks something like
<h1>Model_2 object</h1>
<form method="post" action="">
<tr>
<td>Model1 object name</td>
<td><input type="checkbox" name="model1_id_1" /></td>
</td>
<tr>
<td>Model1 object name</td>
<td><input type="checkbox" name="model1_id_2" checked="checked" /></td>
</td>
<tr>
<td>Model1 object name</td>
<td><input type="checkbox" name="model1_id_3" /></td>
</tr>
<input type="submit" />
</form>
Edit 1
I have made something that seems to work, but I'm not sure if it's correctly done.
I have a view
class Model2Detail(ModelFormSetView):
model = Model1
template_name = 'tpl.html'
form_class = PairingForm
extra = 0
def get_queryset(self):
self.object = get_object_or_404(Model2, slug=self.kwargs['slug'])
return Model1.objects.all() # those objects with ForeignKey field
def formset_valid(self, formset):
for form in formset:
form.instance.foreign_key_field = self.object # set Model1's ForeignKey field
form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return self.object.get_absolute_url()
and a form
class PairingForm(ModelForm):
is_linked = BooleanField(required=False)
class Meta:
fields = ()
model = Model2 # those objects __without__ ForeignKey field
def __init__(self, *args, **kwargs):
super(PairingForm, self).__init__(*args, **kwargs)
if self.instance.foreign_key_field: # if object already paired
self.fields['is_linked'].initial = True
def save(self, commit=True, force_insert=False, force_update=False, *args, **kwargs):
obj = super(PairingForm, self).save(commit=False, *args, **kwargs)
if self.cleaned_data['is_linked']:
obj.foreign_key_field = self.instance.entry
else:
obj.foreign_key_field = None # remove pairing
obj.save()
To me it seems wrong that I try setting the ForeignKey field in both the view and the form, but I don't know how it should be.
Edit 2
My code works, but I actually don't know why. If I am not setting the foreign key field in formset_valid
, it doesn't work any longer, so I think something is wrong. Shouldn't I be able to make it work without overwriting formset_valid
at all? Am I using the right model in Meta.model in my form?
I think it is good practice to modify only one type of object in a form. This keeps things separated and, I believe, leads to a cleaner design with expected behaviors.
With that in mind, I think you should think of this not as "editing a Model_2 object" but more as "editing a bunch of Model_1 objects" by setting or unsetting a value on each one. In that architecture, you might use a form set, each with a checkbox field (say, is_linked
). In the formset's save_new
or save_existing
method, you could check that field and set the foreign key accordingly on the particular object being saved.
Your updated version looks pretty good. The only problem I see is that your formset_valid
method seems to set the foreign key field for every object in the form, but you really only want that to be set when is_linked
is True, right? It seems to me that ParingForm
actually does the right thing on save, so you shouldn't need to set the value in formset_valid
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.