I opened up a prior issue on SO regarding manytomany fields not being saved in Django Createview here. Django CreateView With ManyToManyField After troubleshooting most of today, I have found that this code actually works:
class CreateAuthorView(LoginRequiredMixin,CreateView):
def form_valid(self, form):
instance = form.save(commit=False)
instance.save()
instance = form.save()
if instance.access_level == "Custom":
obj = NewAuthor.objects.get(secret=instance.name)
obj.access.add(instance.created_by.id)
print(instance.created_by.id)
print(obj.access.all())
instance = form.save()
obj.save()
form.save_m2m()
instance = form.save()
return super(CreateAuthorView, self).form_valid(form)
When I issue the print(obj.access.all()) I can see in my console that the
obj.access.add(instance.created_by.id)
Line of code actually does exactly what I want it to do...it adds the created_by.id to the access(ManyToManyField) field that I have defined in my model. However, when the record actually gets cut, only the values that the user selected in the form are added to the access field, and the created_by.id never makes it to the database.
Should I be overriding CreateView somewhere else in order for the created_by to take affect? It appears as if my initial update in form_valid is being overwritten is what I suspect. Actually I've proven it because my update is in fact in my console but not making it to the database. Thanks in advance for any thoughts on how best to solve.
I found the answer to my question via this SO question. It turns out you have to override SAVE in the ModelForm in order to save M2M fields. Save Many-To-Many Field Django Forms
This one was tricky.
Related
The describtion of this in docs seems very sparse and unclear to me I am asking here. So what is exactly doing the form_valid method here? From what I understand, it gets triggered with POST method and it is kinda calling save() in the last line.
form.instance.entry_author=self.request.user in this line I understand that we are setting the current user to be the author but I dont understand why form referances to instance and also where did the form get from? I suppose its in-built in the form-valid function?
class CreateEntryView(CreateView):
model = Entry
template_name='entries/create_entry.html'
fields = ['entry_title','entry_text']
def form_valid(self, form):
form.instance.entry_author=self.request.user
return super().form_valid(form)
CreateView is a generic view which does a few things for you automatically without you having to write the logic yourself. One of those things is creating a Form. You indicated the model to use, which is Entry. Based on the fields, CreateView creates a form and uses that form.
From the docs: form_valid saves the form instance, sets the current object for the view, and redirects to get_success_url().
You can override this if you have any special requirements. Notice that entry_author is not included in the fields so it will not be present in the form. The idea here is to set the entry_author automatically instead of the user choosing the author in the form.
What is the best procedure in Django for saving a form related to another model without the use of inline formsets?
Problem setup:
Model Address is related by a foreign key to Model User
Each User can have multiple Addresses. I want to add a new address to an User.
views.py
In the AddAddress class (extending CreateView) the form.errors has the error
{'user': ['This field is required.']}
The user pk is in the url /address/add/<int:pk>
First, as Daniel Roseman noted, have to make sure the field "user" does not exist in the fields list of the form. This will make sure that the form is valid.
Override the form_valid method in the view class to save the form without commiting, then setting the required user to the resulting instance and then invoking the save directly on the it.
def form_valid(self, form):
address_obj = form.save(False)
address_obj.user = User.objects.get(pk=self.kwargs['pk'])
return HttpResponseRedirect(self.get_success_url())
Thanks in advance for reading this. I can't wrap my head around it and it's getting quite frustrating by now.
We have the following registration form:
class RegistrationForm(forms.ModelForm):
class Meta:
model = Register
fields = ('name', 'company_name')
def clean(self):
if is not self.cleaned_data.get('card').is_available():
raise forms.ValidationError(_('Error'))
The Register model includes a card linked to a Card model. This includes is_available() which functionally works.
Our flow is:
The end user selects the card which lists all registrations for it.
They click the 'Add registration'-button which brings them to cards/{PK}/add.
The Add registration-button is a generic.View. In post(self, request, pk) I have the following code:
form = RegistrationForm(request.POST)
But how do I pass it the contents of Card.objects.get(pk=pk) to it?
I tried:
data = request.POST.copy()
data['card'] = pk
form = RegistrationForm(data)
But I think because card is not included in fields it gets lost somewhere, which makes sense from a sanitize-all-input-point of view, but I would very much like to add the card dynamically, in this case.
Any ideas?
So, just use CreateView and study how it does things using the linked site.
There is no need to use generic.View as it's the basic of basics. You only want to implement all this logic using generic.View to get more familiar with the way things work or if you need some very special form handling.
The short version would be:
from django.views import generic
from myapp.forms import RegistrationForm
class CardCreateView(generic.CreateView):
form_class = RegistrationForm
ModelForm has a save method. The correct way to solve this is to use it with commit=False, that will return an object that hasn’t yet been saved to the database. Then you can alter that object before finally saving it.
This is explained here in the docs
So this is what your code should look like:
form = RegistrationForm(request.POST)
form.save(commit=False)
form.card = Card.objects.get(pk=pk)
form.save_m2m()
save_m2m should be used if your model has many-to-many relationships with other models. In my case, it was a OneToOne, so I used save() instead.
If you use a CreateView instead of the generic View, the snippet above should go into your overridden form_valid method
Please this as a consideration question. Maybe somebody will use one of the
solutions below.
I have a couple of models which contain a ForeignKey(User) field.
My class-based create views are derived from the generic CreateView.
There are two options to save the associated user when adding a new object:
Saving the form in the views by overriding the form_valid method;
this doesn't expose user_id (and other not mentioned here data that should not be exposed)
class CreateOfferView(CreateView):
model = Offer
form_class = SomeModelFormWithUserFieldExcluded
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
instance.save()
Saving the form with user id stored (and exposed) in a hidden field.
Here's the tricky part. There are more models with user field... so
when creating a form I need to fill the user field with initial (currently logged in) user and also I need to make that field hidden. For this purpose I've used my OwnFormMixin
class OwnFormMixin(object):
def get_form(self, form_class):
form = super(OwnFormMixin, self).get_form(form_class)
form.fields['user'].widget = forms.HiddenInput()
def get_initial(self):
initial = super(OwnFormMixin, self).get_initial()
initial['user'] = self.request.user.pk
#I could also do this in get_form() with form.fields['user'].initial
class CreateOfferView(OwnFormMixin, CreateView):
model = Offer
form_class = SomeModelFormWithAllFields
There are more CreateXXXView using the OwnFormMixin..
How do you save your user data in the forms?
Hidden vs. saving directly in your views? What are pros/cons?
Unless you're allowing users to modify that ForeignKeyField, there's no reason to include it in a form — I'd go with your first solution of using exclude to keep the user field out of your ModelForm, and setting the user from request.user. In fact, the Django documentation now has an example along these exact lines.
You have the advantage of not having to secure against manipulation of the user_id parameter, not exposing your internal user IDs and not having to worry about the different Create vs. Update cases. A slight disadvantage is that if you ever need the ability to change an object's associated User you'll need to start again.
I have a form that I use to display several fields from a record to the user. However, the user should not be able to update all the fields that are displayed. How do I enforce this? It would nice if I could specify which fields to save when calling form.save, but I couldn't get this to work. Here's some of the code:
obj = get_object_or_404(Record, pk=record_id)
if request.method == 'POST':
form = forms.RecordForm(request.POST, instance=obj)
if form.is_valid():
form.save()
I don't think using exclude or fields in the form's Meta definition will work as this will only display the fields the user is allowed to update.
You can override the form's save() method:
class MyModelForm(forms.ModelForm):
def save(self, commit=True):
if self.instance.pk is None:
fail_message = 'created'
else:
fail_message = 'changed'
exclude = ['field_a', 'field_b'] #fields to exclude from saving
return save_instance(self, self.instance, self._meta.fields,
fail_message, commit, construct=False,
exclude=exclude)
Option 1: exclude those fields, and use your template to display the data that should not be changed completely outside of the form itself. It sounds to me like they're not really part of the form, if the user can't change them.
Option 2: In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?
take this answer to mark your fields as read only... but understand there's no server side security here, so you would want to do something like getting the target model before you update it, and update those offending form fields to the existing data, before you save the form.