Reputation: 169
I'm working on a test application in Django and have run in to an issue I've been unable to solve.
I have two models, Farm and Product which have a One to Many relationship. When creating a Farm you can add multiple images which gets added as individual products with the Farm as the foreign key.
As I was working on being able to update the name of the farm I also wanted to add the ability to add more products on the same page. So I wrote a post function that is similiar to the one I used for creating the farm. However when I submit the update it doesn't only update and add the new products, it also creates a new farm object with the same name.
I think I have to get the correct instance for this to work but I don't have enough experience with Django to know where I need to implement those changes. (I might also have to change from the UpdateView to something else, if so please let me know!)
Here is my UpdateView:
class FarmUpdateView(UpdateView):
model = Farm
fields = ['title']
def post(self, request, *args, **kwargs):
farm = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('images')
if form.is_valid():
title = form.cleaned_data['title']
updateFarm = farm
updateFarm.title = title
updateFarm.save()
farm_id = updateFarm
for f in files:
Product.objects.create(image=f, farm=farm_id)
return self.form_valid(form)
else:
return self.form_invalid(form)
And here is my template:
<form method="post" class="farm-form" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<label for="farm-image">Images</label>
<input type="file" name="images" class="form-control-file" id="farm-image" multiple>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Upvotes: 2
Views: 1304
Reputation: 477686
The reason this fails is because you did not set self.object
before making a form with get_form
. As we can see in the source code of get_form_kwargs
[GitHub], it will pass self.object
as instance, if it exists:
def get_form_kwargs(self): """Return the keyword arguments for instantiating the form.""" kwargs = super().get_form_kwargs() if hasattr(self, 'object'): kwargs.update({'instance': self.object}) return kwargs
So that means your self.get_form
will construct a form, without an instance, and thus create a record.
You furthermore also do too much manual work yourself. Django's modelforms actually can remove a lot of boilerplate code. You can implement the creation of the Product
s in the form_valid
method, and let Django do most of the work for you:
class FarmUpdateView(UpdateView):
model = Farm
fields = ['title']
def form_valid(self, form):
farm = form.instance
products = [
Product(image=f, farm_id=farm) for f in request.FILES.getlist('images')
]
Product.objects.bulk_create(products)
super().form_valid(form)
Upvotes: 6