What is the best way to pass a query variable to a model using CreateView

I am working on a messaging system where I want to set the sender of a message based on the current user.

class Message(models.Model): originator = models.ForeignKey(User, related_name='+') destination = models.ForeignKey(User, related_name='+') subject = models.CharField(max_length=100) content = models.TextField() 

I use ModelForm and CreateView to represent this:

 class MessageForm(forms.ModelForm): class Meta: model = Message fields = ('destination', 'subject', 'content') 

Therefore, before saving this form, the originator must be set as the current user. I don’t think that overriding the save method of the model is appropriate here, so I was going to do this in the form of save , but I do not have access to the query variable. In another CreateView post, the recommendation was to override the get_form_kwargs method:

 class MyFormView(FormView): def get_form_kwargs(self): # pass "user" keyword argument with the current user to your form kwargs = super(MyFormView, self).get_form_kwargs() kwargs['user'] = self.request.user return kwargs 

However, this does not work, since you cannot pass kwarg user to ModelForm, since ModelForm does not accept user arguments.

What is the best (cleanest and most practical) way to update the originator variable with user information?

+4
source share
1 answer

In a discussion with yuji-tomita-tomita, he suggested the following, which I would like to share:

The first method is based on its source code by sending user kwarg to the form using get_form_kwargs , then you should change your model model to look like this:

 class MyModelForm(forms.ModelForm): def __init__(self, *args, **kwargs): self.user = self.kwargs.pop('user', None) super(MyModelForm, self).__init__(*args, **kwargs) 

Thus, the original __init__ function receives the arguments that it expects.

But the preferred method that he proposed was:

 class MyView(CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.user = self.request.user obj.save() return super(MyView, self).form_valid(form) 

It works very well. When the form.save(commit=False) method executes, it fills self.instance in the form object with the same model instance, it returns to our obj variable. When you update obj by doing obj.user = self.request.user and saving it, the form object has a reference to that exact same object, and therefore the form object is already completed here. When you pass it to the original form_valid CreateView method, it has all the data and will be successfully inserted into the database.

If anyone has another way to do this, I would love to hear about it!

+3
source

All Articles