Get saved object of a model form in Django? - python

I just want to access model details just after posting it with model form in Django. This guy also had asked the same thing but when i try the
accepted answer, it returns none type value.
Here is my code in 'views.py':
if request.method == 'POST':
if request.user.is_authenticated():
form = PostStoryForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.author = request.user
new_post = obj.save()
print(new_post)
The Code above saves the form to the database successfully but 'new_post' variable is 'None'. For example when i tried to access 'new_post.title' which is a field in my model, it returns 'AttributeError' which says 'NoneType' object has no attribute 'title'
what am i doing wrong?

The models save() method does not return the instance
obj.author = request.user
obj.save() # this does not return anything. It just saves the instance it is called on.
Your instance already has the author set.
To access auto populated fields that haven't been set yet, you will have to fetch it from the database again after saving. This is the case, when the instance you called save() on did not already exist before.
new_obj = MyModel.objects.get(id=obj.id)

Related

Ceating two objects instead of one in Django

I want to create an object with transmitting some data from other model. And it works good, but instead of creation one object of model, I got two objects.
I create one object and try modify it, but it saves two objects, created and modified. I want to save only one object, which was modified. I am using the approach that was suggested to me: Django instance in model form
Views
topic = Topic.objects.get(id=pk)
room = Room.objects.create(topic=topic)
form = RoomForm(request.POST, instance=room)
if request.method == 'POST':
if form.is_valid():
room = form.save(commit=False)
room.host=request.user
room.save()
return redirect('home')
Don't create an object yourself; let the form do this. With your approach, you create one in the GET request, and one in the POST request:
def my_view(request, pk):
topic = Topic.objects.get(id=pk)
# no create
if request.method == 'POST':
form = RoomForm(request.POST)
if form.is_valid():
form.instance.topic_id = pk
form.instance.host = request.user
form.save()
return redirect('home')
else:
form = RoomForm()
# …
if you want to modify an object which created before just do this.
search from your model and update the field you want
Topic.objects.filter(id=pk).update(fields = something)
that it bro.
remember use if when you want to sure that the object you choose is the right one

In Django, ModelAdmin, what is the difference between save_form() and save_formset()?

Can somebody explain the differences and/or similarities between save_form and save_formset from ModelAdmin?
The only things i could find about this is from source code.
def save_form(self, request, form, change):
"""
Given a ModelForm return an unsaved instance. ``change`` is True if
the object is being changed, and False if it's being added.
"""
return form.save(commit=False)
def save_formset(self, request, form, formset, change):
"""
Given an inline formset save it to the database.
"""
formset.save()
And the docs have only this about save_formset (https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_formset)
The save_formset method is given the HttpRequest, the parent ModelForm
instance and a boolean value based on whether it is adding or changing
the parent object.
A formset is a bunch of equal forms. For example if you have a form where a user enters a food he likes, but then you want the user to be able to keep adding more, as many as he wants, then the formset will generate forms with an input for food, and will generate new, blank inputs, as the list grows. When formset.save() is called, all those forms are saved, and that is what save_formset() is doing.
As shown in the example in the docs, you can override this, for example to add a user to each form in the formset before committing the changes to the database:
class ArticleAdmin(admin.ModelAdmin):
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for instance in instances:
instance.user = request.user
instance.save()
formset.save_m2m()
Now, save_form(), is just to save a regular form, but as you can see it has commit=False, so the form is not saved to the database yet. Data can be added to the form until it is ready to be committed to the database. If the form is based on a model with a ManyToManyField, that field cannot be saved until the model instance is first saved, so this is where form.save_m2m() in the following function in the same source code:
def save_related(self, request, form, formsets, change):
"""
Given the ``HttpRequest``, the parent ``ModelForm`` instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
"""
form.save_m2m()
for formset in formsets:
self.save_formset(request, form, formset, change=change)
Note
I'm relatively new to formsets, and have never myself modified or used ModelAdmin methods, so if anyone sees anything wrong with my summary, let me know.

MutipleCheckBox saving to Database with Django

I'm trying to find some kind of canonical reference for this problem where I use the follow type model:
class MyPreferencesForm(forms.Form):
MyGenderPref = forms.MultipleChoiceField(choices=GENDER_CHOICES, widget=forms.CheckboxSelectMultiple())
and the view
def GoPreferences(request):
if request.method == "POST":
f = MyPreferencesForm(request.POST)
if f.is_valid():
model_instance = f.save(commit=False)
model_instance.save()
f.save_m2m()
return redirect('/')
else:
f = MyPreferencesForm()
return render(request, "mypreferences.html", {'form': f})
However I tried to follow what I thought was sensible and include the many to many. But I still cannot make this work. My error is the following:
Exception Type: AttributeError
Exception Value:
'MyPreferencesForm' object has no attribute 'save'
The error emanates from line containing model_instance = f.save(commit=False)
save is available only for forms inherited from ModelForm objects. Here, you are inheriting form forms.Form Hence the error.
Either inherit the form from forms.ModelForm and specify a Meta attribute
class MyPreferencesForm(forms.ModelForm):
MyGenderPref = forms.MultipleChoiceField(choices=GENDER_CHOICES, widget=forms.CheckboxSelectMultiple())
class Meta:
model = MyModel
You can read more on ModelForms here - You might have to modify your form slightly based on your specific requirements.
OR
model_instance = MyModel.objects.create(**form.cleaned_data) #manage manually
If your m2m tables in your models.py uses through then you'll need to manage the saving manually using object.create and you can't use save_m2m() or save()

Django: using ._get_deleted_forms and custom formset saving

I'm attempting to provide some custom formset handling. The user has the option of deleting a form and adding a form. Within the same function I'm trying to remove the associated object and add new objects. This is an example of the code I'm working on:
def addCategories(movie, category_formset):
if category_formset.deleted_forms:
for form in category_formset._get_deleted_forms:
obj_to_remove = form.save(commit=False)
movie.categories.remove(obj_to_remove)
for form in category_formset:
if form.cleaned_data.get('name') is not None:
obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))
movie.categories.add(obj)
movie.save()
The problem is that I don't think I'm using ._get_deleted_forms correctly. It claims that category_formset._get_deleted_forms is not iterable. And I'm not sure if this would work anyway -- since it might just add the deleted object right back to the model in the second for loop. Any ideas?
A workaround that doesn't seem very efficient:
def addCategories(recipe, category_formset):
if category_formset.deleted_forms:
for form in category_formset:
if form in category_formset.deleted_forms:
obj_to_remove = form.save(commit=False)
recipe.categories.remove(obj_to_remove)
else:
if form.cleaned_data.get('name') is not None:
obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))
recipe.categories.add(obj)
else:
for form in category_formset:
if form.cleaned_data.get('name') is not None:
obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))
recipe.categories.add(obj)
recipe.save()

django ModelForm save() method issue

I have a model form:
class SnippetForm(ModelForm):
class Meta:
model = Snippet
exclude = ['author', 'slug']
and I want to be able to edit a particular instance by using this:
def edit_snippet(request, snippet_id):
#look up for that snippet
snippet = get_object_or_404(Snippet, pk=snippet_id)
if request.user.id != snippet.author.id:
return HttpResponseForbidden()
if request.method == 'POST':
form = SnippetForm(data=request.POST, instance=snippet)
if form.is_valid():
form.save()
return HttpResponseRedirect(snippet.get_absolute_url())
else:
form = SnippetForm(instance=snippet)
return render_to_response(SNIPPET_EDIT_TEMPLATE,
{'form':form, 'add':False, 'user':request.user},
RequestContext(request))
Notice that at the line
form = SnippetForm(data=request.POST, instance=snippet)
, I created a form that use the data supplied from the user, and bound it with the instance found using the primary key (received from the url). According to django documentation, when I call save() the existing instance should be updated with POSTED data. Instead, what I see is a new object is created and saved into the database. What went wrong? Thanks a lot.
[Edit] This is really embarrassed. The code indeed has nothing wrong with it. The only thing that messed up the whole thing was the action I put in the template (as I use a same template for add and edit a snippet)....Thanks a lot for your help, really appreciate that.
I don't see why it would happen. What version of django is it?
In any case, you can manually force update passing the corresponding argument.
form = SnippetForm(data=request.POST, instance=snippet, force_update=True)

Categories