Passing parameters from partial form to model during save Django - django

I have a model with many fields, for which I am creating two partial forms
#model
class Line_Settings(models.Model):
....
line = models.ForeignKey(Line)
All = models.BooleanField(default=False)
Busy = models.BooleanField(default=False)
MOH = models.CharField(max_length=100, blank=True, null=True)
PLAR = models.CharField(max_length=100, blank=True, null=True)
....
def save(self, commit = True, *args, **kwargs):
....
#Partial model form1
class General(ModelForm):
class Meta:
model = Line_Settings
fields = ('MOH','PLAR')
#Partial model form2
class Common(ModelForm):
class Meta:
model = Line_Settings
fields = ('All','Busy')
I have overwritten the save for the Line_Settings model to do additional logic.
I need to be able to pass some parameters to the overwritten save method to use in my logic.
In my views I fill up the two partials forms with post data and can call save.
call_forwards = Common(request.POST, instance=line_settings)
general = General(request.POST, instance=line_settings)
I need to pass a parameter to the save like so:
call_forwards.save(parameter="value")
general.save(parameter="value")
I have referred to passing an argument to a custom save() method
I can get access to the parameter if I overwrite the save on my partial form.
# overwritten save of partial form
def save(self, parameter, commit=True):
print("In save overwrite Partial form Common "+str(parameter))
#how Can I pass this parameter to the model save overwirite?
super(Common, self).save(commit)
From the partial form, how do I make the parameter reach my original model(Line_Settings) save overwrite?
Can this be done?
Thanks in advance for reading!!

I was able to achieve this by defining a parameter in my original models __init__ method
def __init__(self, *args, **kwargs):
self.parameter= None
super(Line_Settings, self).__init__(*args, **kwargs)
Then in the partial form, I could access this parameter and set it to value passed during save
def save(self, *args, **kwargs):
self.instance.parameter = kwargs.pop('parameter', None)
super(Common, self).save(*args, **kwargs)
In my view I called the save as :
common = Common(request.POST, instance=line_settings)
common.save(parameter="something")

Related

Django ckeditor unable to save initial values of a form field after editing

I am using a class based create view to show a form to the end user. One of the fields of the form shows an initial value, which would be changed by the end user, before saving the values to the database.
The form looks like the below:
class R1Form(forms.ModelForm):
interview_date = forms.DateField(widget=DateInput())
feedback = forms.CharField(widget=CKEditorWidget())
def __init__(self, *args, **kwargs):
super(R1Form, self).__init__(*args, **kwargs)
self.initial['feedback'] = template_R1.objects.all().first().template
class Meta:
model = R1
fields = ['interview_date', 'interviewers', 'feedback', 'comment', 'recommended_level', 'progress']
widgets = {'feedback': CKEditorWidget()}
In the above form the field called 'feedback' shows an initial value from the database.
The class based, create view looks like below:
class R1CreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = R1
form_class = R1Form
template_name = "interviews/r1/create.html"
# This a quick way to populate fields not present in the model form, but required in the model.
def form_valid(self, form):
form.instance.candidate_id = self.kwargs['candidate']
return super().form_valid(form)
# Required because with HTMX we need to provide a url for post request, and our url also requires additional parameters
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page'] = self.request.GET.get('page', 1)
context['candidate_pk'] = self.kwargs['candidate']
return context
def get_success_url(self):
return reverse_lazy("cvscreenings-success", kwargs={'candidate': self.kwargs['candidate'], 'message': 'Saved!'})
def test_func(self):
return True
When the form is shown to the end user, the initial value (template_R1.objects.all().first().template) is correctly displayed to the end user. However, upon editing, this edited value is not saved to the database. The database only saves the initial value, but not the edited version of the initial value.
The database model is defined as below:
class R1(models.Model):
candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE)
interview_date = models.DateField(default=timezone.now)
interviewers = models.ManyToManyField(User, blank=False)
feedback = RichTextField(null=True)
comment = models.TextField(null=True, blank=True)
recommended_level = models.ForeignKey(Rank, on_delete=models.SET_NULL, null=True)
progress = models.CharField(choices=[('PROGRESS', 'Progress'),('REJECT', 'Reject')], default='PROGRESS', max_length=28, null=True)
The url pattern for the create view is defined as below:
path('r1s/create/<int:candidate>', views.R1CreateView.as_view(), name="r1s-create"),

Creating dynamic ModelChoiseField from users List objects

I have been trying for awhile now without any luck.. I have model Like this:
class List(models.Model):
name = models.CharField(max_length=100, default="")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
def __str__(self):
returnself.name
class Meta:
unique_together = ['name', 'user']
Every user can create their own lists and add values to those lists. I have adding values and everything else working but to the form that adds these values I would somehow need to filter to show only users own lists, now its showing all lists created by every user... this is the form:
class data_form(forms.Form):
user_lists = List.objects.all()
selection = forms.ModelChoiceField(queryset=user_lists)
data = forms.IntegerField()
Any ideas how to filter it? I have tempoary "list.objects.all()" since dont want it to give error that crashes the server. I have watched a ton of examples on stackoverflow but none of them seems to be exact thing that I am looking for.. Thanks already for asnwers! :)
You need to get hold of the current user, e.g. like so or so.
That is, you pass request.user to the form when instantiating it in your view:
frm = DataForm(user=request.user)
In the __init__ of your form class, you can then assign the user-filtered queryset to your field:
class DataForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(DataForm, self).__init__(*args, **kwargs)
self.fields['selection'].queryset = List.objects.filter(user=user)
You can set your form to take the user when initialized, and from there get a new queryset filtered by user.
class DataForm(forms.Form):
selection = forms.ModelChoiceField(queryset=List.objects.none())
data = forms.IntegerField()
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['selection'].queryset = List.objects.filter(user=user)
You would inititialize the form like this:
form = DataForm(request.user)

Auto create related model

I am wondering if it's possible to auto create a related model upon creation of the first model.
This is the models
class Team(models.Model):
name = models.CharField(max_length=55)
class TeamMember(models.Model):
team = models.ForeignKey('Team', on_delete=models.CASCADE, null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False)
So what I want to do is something like this on the 'Team' model
class Team(models.Model):
name = models.CharField(max_length=55)
#on_new.do_this
TeamMember.team = self
TeamMember.user = request.user
TeamMember.save()
I have tried to find any documentation about this. But only found some example about onetoonefields. But nothing about this.
Appreciate any help. Cheers!
I am assuming you are using forms to create team.
There is no direct way to create the TeamMember instance without the current user(via request). request is available in views only(unless you are using special middleware or third party library to access it), so we can send it form and create the user by overriding the save method of the modelform.
So you can try like this:
# Override the model form's save method to create related object
class TeamForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(TeamForm, self).__init__(*args, **kwargs)
class Meta:
model = Team
def save(self, **kwargs):
user = self.request.user
instance = super(TeamForm, self).save(**kwargs)
TeamUser.objects.create(team=instance, user=user)
return instance
And use this form in View:
# Update get_form_kwargs methods in create view
class TeamCreateView(CreateView):
form_class = TeamForm
template = 'your_template.html'
def get_form_kwargs(self):
kw = super(TeamCreateView, self).get_form_kwargs()
kw['request'] = self.request
return kw
Update
(from comments)If you have the user FK availble in Team then you can use it to create TeamMember by overriding the save method. Try like this:
class Team(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL)
name = models.CharField(max_length=55)
def save(self, *args, **kwargs): # <-- Override
instance = super(Team, self).save(*args, **kwargs)
TeamMember.objects.create(user=instance.user, team=instance)
return instance

Setting value of Django field inside of Form class

I'm trying to set the value of a Django field inside of the Form class. Here is my model
class Workout(models.Model):
user = models.ForeignKey(User , db_column='userid')
datesubmitted = models.DateField()
workoutdate = models.DateField();
bodyweight = models.FloatField(null=True);
workoutname = models.CharField(max_length=250)
Here is the form class, in which i am attempting to achieve this:
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
def __init__(self,*args, **kwargs):
# this is obviously wrong, I don't know what variable to set self.data to
self.datesubmitted = self.data['datesubmitted']
Ok, sorry guys. I'm passing the request.POST data to the WorkoutForm in my view like this
w = WorkoutForm(request.POST)
However, unfortunately the names of the html elements have different names then the names of the model. For instance, there is no date submitted field in the html. This is effectively a time stamp that is produced and saved in the database.
So I need to be able to save it inside the form class some how, I think.
That is why I am trying to set the datesubmitted field to datetime.datetime.now()
Basically I am using the form class to make the verification easier, and I AM NOT using the form for it's html output, which I completely disregard.
You have to do that in the save method of your form
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
def __init__(self,*args, **kwargs):
super(WorkoutForm, self).__init__(*args, **kwargs)
def save(self, *args, **kw):
instance = super(WorkoutForm, self).save(commit=False)
instance.datesubmitted = datetime.now()
instance.save()
How ever you can set that in your model also to save the current datetime when ever a new object is created:
datesubmitted = models.DateTimeField(auto_now_add=True)
You can set some extra values set in form as:
form = WorkOutForm(curr_datetime = datetime.datetime.now(), request.POST) # passing datetime as a keyword argument
then in form get and set it:
def __init__(self,*args, **kwargs):
self.curr_datetime = kwargs.pop('curr_datetime')
super(WorkoutForm, self).__init__(*args, **kwargs)
You should not be using a ModelForm for this. Use a normal Form, and either in the view or in a method create a new model instance, copy the values, and return the model instance.

How do I add a Foreign Key Field to a ModelForm in Django?

What I would like to do is to display a single form that lets the user:
Enter a document title (from Document model)
Select one of their user_defined_code choices from a drop down list (populated by the UserDefinedCode model)
Type in a unique_code (stored in the Code model)
I'm not sure how to go about displaying the fields for the foreign key relationships in a form. I know in a view you can use document.code_set (for example) to access the related objects for the current document object, but I'm not sure how to apply this to a ModelForm.
My model:
class UserDefinedCode(models.Model):
name = models.CharField(max_length=8)
owner = models.ForeignKey(User)
class Code(models.Model):
user_defined_code = models.ForeignKey(UserDefinedCode)
unique_code = models.CharField(max_length=15)
class Document(models.Model):
title = models.CharField(blank=True, null=True, max_length=200)
code = models.ForeignKey(Code)
active = models.BooleanField(default=True)
My ModelForm
class DocumentForm(ModelForm):
class Meta:
model = Document
In regards to displaying a foreign key field in a form you can use the forms.ModelChoiceField and pass it a queryset.
so, forms.py:
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
def __init__(self, *args, **kwargs):
user = kwargs.pop('user','')
super(DocumentForm, self).__init__(*args, **kwargs)
self.fields['user_defined_code']=forms.ModelChoiceField(queryset=UserDefinedCode.objects.filter(owner=user))
views.py:
def someview(request):
if request.method=='post':
form=DocumentForm(request.POST, user=request.user)
if form.is_valid():
selected_user_defined_code = form.cleaned_data.get('user_defined_code')
#do stuff here
else:
form=DocumentForm(user=request.user)
context = { 'form':form, }
return render_to_response('sometemplate.html', context,
context_instance=RequestContext(request))
from your question:
I know in a view you can use
document.code_set (for example) to
access the related objects for the
current document object, but I'm not
sure how to apply this to a ModelForm.
Actually, your Document objects wouldn't have a .code_set since the FK relationship is defined in your documents model. It is defining a many to one relationship to Code, which means there can be many Document objects per Code object, not the other way around. Your Code objects would have a .document_set. What you can do from the document object is access which Code it is related to using document.code.
edit: I think this will do what you are looking for. (untested)
forms.py:
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
exclude = ('code',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user','')
super(DocumentForm, self).__init__(*args, **kwargs)
self.fields['user_defined_code']=forms.ModelChoiceField(queryset=UserDefinedCode.objects.filter(owner=user))
self.fields['unique_code']=forms.CharField(max_length=15)
views.py:
def someview(request):
if request.method=='post':
form=DocumentForm(request.POST, user=request.user)
if form.is_valid():
uniquecode = form.cleaned_data.get('unique_code')
user_defined_code = form.cleaned_data.get('user_defined_code')
doc_code = Code(user_defined_code=user_defined_code, code=uniquecode)
doc_code.save()
doc = form.save(commit=False)
doc.code = doc_code
doc.save()
return HttpResponse('success')
else:
form=DocumentForm(user=request.user)
context = { 'form':form, }
return render_to_response('sometemplate.html', context,
context_instance=RequestContext(request))
actually you probably want to use get_or_create when creating your Code object instead of this.
doc_code = Code(user_defined_code=user_defined_code, code=uniquecode)