How to update an object from edit form in Django? - django

Possibly a newbie question, so please bear with me.
I have a Django form that edits a certain instance of a Model. In order to know which object is being edited, I have a hidden field containing the id of the object, along with the URL containing the id.
First question: Is having the id of the object in a hidden field the right way of doing it?
My (possibly unfounded) concern with having it only as part of the url is that someone could then open the page of one object id, submit the form to another, and that object will then be overwritten. That's why I'm trying to use a hidden field.
The problem with storing the id in a hidden field is that, on validation of the form, Django complains that the object does not have an unique id (obviously).
Second question: If a unique field is part of a form, how does one tell Django to ignore the fact that that key already exists, in order to update the object?

Why don't you just use ModelForm?
# forms.py
# ...
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
# views.py
# ...
def my_view(request, id):
instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
return redirect('next_view')
return render(request, 'my_template.html', {'form': form})
See https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/#the-save-method for more details.

Update for Django 1.6 and further version
# forms.py
# ...
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
# views.py
def my_view(request, id):
instance = MyModel.objects.get(id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
return redirect('next_view')
return direct_to_template(request, 'my_template.html', {'form': form})

Related

Django Multi Step Form duplicate key value

I'm attempting to implement a multi-step form on Django and am relatively new to the language but am having difficulty when it comes to saving to the data to the backend. Any help would be much appreciated. Spend around 8 hours trying to figure this out myself.
I need to pass the code and name from model Books to People and then insert the other required information on step 2 as this is a separate table model.
There is a foreign key connecting People to Books via the id.
Views.py
#Step1
def step1(request):
initial={'code': request.session.get('code', None),
}
form = PrimaryForm(request.POST or None, initial=initial)
if request.method == 'POST':
if form.is_valid():
return HttpResponseRedirect(reverse('main_app:step2'))
return render(request, 'step1.html', {'form': form})
#Step2
def step2(request):
form = SecondaryForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form1 = form.save(commit=False)
form2 = People.objects.create(code=request.session['code'])
form1.save()
return HttpResponseRedirect(reverse('main_app:finished'))
return render(request, 'step2.html', {'form': form})
Forms.py
#models/forms
class PrimaryForm(forms.ModelForm):
class Meta:
model = People
fields = ('id','code','name',)
class SecondaryForm(forms.ModelForm):
class Meta:
model = Books
fields = ('type','title',)
exclude = ('book_id',)
Error message
insert or update on table "PEOPLE" violates foreign key constraint
DETAIL: Key (id_id_id)=(0) is not present in table "PEOPLE".
The code, name should pass through the forms and at step 2 save the information from both forms.

How to get the ID of the record created in the model after saving it from a Form

Let's say I submit a form to the back-end and I save a record of the model in the following way:
views.py:
def viewName(request):
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
form.save() #I want to get the id of this after it is saved
else:
print (form.errors)
form = ProjectForm()
return render(request, 'index.html', context)
forms.py:
class ProjectForm(ModelForm):
class Meta:
model = Project
fields = '__all__'
Right after saving the form, I would like to get the id of the record for the model.
I tried with form.id and form.pk as I saw in other similar questions without success.
How can I get the id or the pk of the new entry added to the Project model?
form.save() returns the object, so:
obj = form.save()
print(obj.pk)

Django using a form with an ImageField and a User

In Django, the user can upload a comment with the image.
from sorl.thumbnail import ImageField
class Comment(models.Model):
count_votes = models.Integer(default=0)
user = models.ForeignKey(User)
thumb = ImageField(upload_to="thumbnails")
# ...
This is what I am trying to do :
# views.py
def add_comment(request):
if request.method == 'POST' and request.user.is_authenticated():
comment = Comment(user=request.user)
form = CommentForm(request.POST, request.FILES, instance=comment)
if form.is_valid():
form.save()
# ...
# forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
But there are some errors :
none of the fields are filled
the count_votes is not defaulted to 0 as I would like to
the user is not taken into account either
the image is said to be empty too
How can I achieve that ? I have read many questions on SO and tried various other things, like fill in things in the __init__ of the form, use initial instead of instance, ...
First, make sure in your template you have enctype="multipart/form-data" in your <form> tag, otherwise the image file will not get uploaded and your form will not validate (and thus, nothing will be added to the database).
In addition, you need to fix your views. Start by using the login_required decorator so that your view is restricted to logged-in users, and then fix your form logic:
from django.shortcuts import redirect, render
from django.contrib.auth.decorators import login_required
#login_required
def add_comment(request):
form = CommentForm(request.POST or None, request.FILES or None)
if form.is_valid():
obj = form.save(commit=False) # create the record, but don't save it
obj.user = request.user # add the user from the request
obj.save() # now save the record
return redirect('/')
return render(request, 'template.html', {'form': form})
Finally, in your form exclude the user because you will be adding it later. In fact, your form should just have the comment and image field. You don't need to include the count_votes field because it already has a default value; unless you want the user to modify this field.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('thumb', 'comment',)

How to add model with ImageField using form in a correct way in django

I have a ModelForm containing a field: image = models.ImageField:
class InstanceForm(ModelForm):
class Meta:
model = Instance
exclude = ('created_at','author',)
And my view is:
def add_instance(request):
if request.user.is_authenticated():
if request.POST:
form=InstanceForm(request.POST,request.FILES)
if form.is_valid():
new_instance=form.save(commit=False)
new_instance.author=request.user.username
new_instance.save()
locals().update(csrf(request))
return render_to_response(...)
else:
return render_to_response(...)
else:
form=InstanceForm()
return render_to_response(...)
else: return HttpResponse(...)
When my form is not valid it shows not only errors, but field 'image' without path to image. It's working in this way, even if I have chosen image at first using Browse.

Django model form using forms.ModelMultipleChoiceField

I have a ModelForm in my Django app that uses a forms.ModelMultipleChoiceField, which displays as a forms.CheckboxSelectMultiple widget on the form. This ModelForm is used to select/de-select values for a many-to-many relation. Here's the problem: when you uncheck all of the checkboxes and save the form, it doesn't save. If you uncheck all but 1, it does save properly.
Are there any tricks I'm missing here about model forms and many-to-many relations? Am I encountering a bug? I'm new to Django. Thanks in advance.
Custom Field:
class NetworkMessageChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return obj.display_message
Model Form:
class MessageTemplateForm(forms.ModelForm):
network_messages = NetworkMessageChoiceField(queryset=NetworkMessageTemplate.objects,
widget=forms.CheckboxSelectMultiple())
class Meta:
model = UserProfile
fields = ('network_messages',)
View that saves form:
def save_message_templates(request, extra_context=dict()):
try:
profile_obj = request.user.get_profile()
except ObjectDoesNotExist:
profile_obj = UserProfile(user=request.user)
if request.method == 'POST':
form = MessageTemplateForm(request.POST, instance=profile_obj)
if form.is_valid():
form.save()
return redirect('/')
return index(request, message_template_form=form)
Edit:
My form field was missing Required=False.
class MessageTemplateForm(forms.ModelForm):
network_messages = NetworkMessageChoiceField(queryset=NetworkMessageTemplate.objects,
widget=forms.CheckboxSelectMultiple(),
required=False)
class Meta:
model = UserProfile
fields = ('network_messages',)
You didn't paste what your model looks like, so I am guessing that network_messages field in your model is required. If that is the case, then when you attempt to submit the form with the value of that field as NULL (empty), then form.is_valid() is not returning True and therefore your form.save() is never being executed.
Have you tried executing this stuff from an interactive shell, instantiating the form and attempting to manually save() it?