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.
Related
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)
I've been struggling with this issue all day and hope someone can help.
I have all my hierarchies classified by category in the same table.
during the form creation, I want to separate each hierarchy by category and render it using a ModelMutipleChoiceField his way not all hierarchies are displayed together.
The problem comes when the form is submitted, as I need to go through each ModelMutipleChoiceField field and get the selected values and copy these to the model field before saving the form. however, I am not able to iterate through the ModelMutipleChoiceField and get the selected values. I also don't know how to set these values on the ModelField
NOTE: The number of hierarchies can vary.
here is my code:
I'm using Django MPTT and create my hierarchy structure using 2 models.
one is the category(Hierarchy) and the other is the nodes of the hierarchy (HierarchyNode_MPTT).
Then I created a separate model that has ManyToManyField pointing to the HierarchyNode_MPTT.
Models.py
class Hierarchy(models.Model):
ID = kp.ObjectIDField()
name = kp.ObjectNameField()
ext_hierarchy = kp.ObjectTechnicalID()
seq_no = kp.SeqNoField(unique=True)
mptt_seq_no = models.PositiveIntegerField()
class HierarchyNode_MPTT(MPTTModel):
id = kp.ObjectIDField()
name = kp.ObjectNameField()
description = kp.ObjectDescriptionField()
ext_node_id = kp.ObjectShortNameField()
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
hierarchy = models.ForeignKey(Hierarchy, on_delete=models.CASCADE, null=True, blank=True, related_name='children')
class Configuration(models.Model):
uuid = kp.ObjectIDField()
name = kp.ObjectNameField()
description = kp.ObjectDescriptionField()
hierarchy_nodes = models.ManyToManyField(HierarchyNode_MPTT)
Then I created the form and implement the init method to automatically create as many hierarchies as I need.
form.py
class ConfigurationCreateForm(forms.ModelForm):
class Meta:
model = ForecastConfiguration
exclude = ['uuid', 'hierarchy_nodes']
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
hierarchies = Hierarchy.objects.all()
for hierarchy in hierarchies:
field_name = 'hierarchy_%s' % (hierarchy.mptt_seq_no,)
self.fields[field_name] = TreeNodeMultipleChoiceField(queryset=HierarchyNode_MPTT.objects.all().filter(hierarchy=hierarchy),label=hierarchy.name, required=True)
try:
self.initial[field_name] = HierarchyNode_MPTT.objects.root_node(tree_id=hierarchy.mptt_seq_no)
except IndexError:
self.initial[field_name] = ''
def copy_hierarchies(self, *args, **kwargs):
hierarchies = Hierarchy.objects.all()
choice_list = list()
for hierarchy in hierarchies:
field_name = 'hierarchy_%s' % (hierarchy.mptt_seq_no,)
selected_values = self.cleaned_data.get(field_name)
for selection in selected_values:
choice_list.append(selection)
self.initial['hierarchy_nodes'] = choice_list
Finally, the idea was to implement the post method on the View to loop over the created hierarchies and then assign the value to the model field called 'hierarchy_nodes'
view.py
class ConfigurationCreateView(CreateView):
model = Configuration
form_class = ConfigurationCreateForm
template_name = 'frontend/base/config_create.html'
def get(self, request, *args, **kwargs):
form = ConfigurationCreateForm(user=request.user)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
form.copy_hierarchies(*args, **kwargs)
if form.is_valid():
fcc_form = form.save(commit=True)
messages.add_message(self.request, messages.INFO, 'Your Forecast Configurations has been saved')
return redirect(reverse('planning_detail', kwargs={'uuid': self.fcc_form.uuid}))
else:
messages.add_message(self.request, messages.ERROR, 'Error when creating the Forecast Configuration')
return render(request, self.template_name, {'form': form})
As you can see I created a method in my form called copy_hierarchies which is where I was planning to copy the hierarchy values, this is the method where I'm having problems.
if there is an easier way to perform this using Javascript, I'm open to these options.
Thanks in advance.
I wasn't able to solve this using multi-choice field, however, the following is the solution for a ChoiceField (single selection)
1) Changed my view.py post method to save the object.
2) After the model is saved I loop over the request input filed and append the values to the created instance.
3) Save the instance.
4) delete my copy_hierarchies method in forms.py
here is the code snippet created in views.py
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
fcc = form.save()
for key in self.request.POST:
# check only the ones w/ 'hierarchy_#'
if key.startswith('hierarchy_'):
# get form field object
id = self.request.POST[key]
node = HierarchyNode_MPTT.objects.get(id=id)
# add to object instance
fcc.hierarchy_nodes.add(node)
fcc.save()
I am facing the following scenario: I have a Django model class called Contact, which looks something like:
class Contact(models.Model):
first_name = models.CharField(max_length=70)
last_name = models.CharField(max_length=70)
company = models.ForeignKey(Company) // should be disabled in user-facing forms
organizations = models.ManyToManyField(Organization) // should be disabled and hidden in user-facing forms
// some other fields not relevant to this question
Both users of the app and administrators should be able to create objects of type Contact and store it in the database. However, for a user this should be restricted in the way that he cannot freely chose the company field of a Contact object. For this, I have created a base ModelForm called ContactForm, intended to be used by administrators, and a restricted user-facing child class called RestrictedContactForm. The code looks as follows:
class ContactForm(forms.modelForm):
class Meta:
model = Contact
fields = ['first_name', 'last_name', 'company', 'organizations']
class RestrictedContactForm(ContactForm):
class Meta(ContactForm.Meta):
widgets = {'organizations': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(RestrictedContactForm, self).__init__(*args, **kwargs)
// Maybe populate company and organization here somehow?
self.fields['company'].disabled = True
self.fields['organization'].disabled = True
The RestrictedContactForm is rendered to the user once he decides to create a new contact. Clearly, as both the company and organization fields are mandatory, they need to be manually injected somehow. It is exactly here where my problem lies: I haven't managed to populate these fields by hand.
Below you can find an outline of the view function implementing the logic of a user initiated creation.
def create_contact(request, company_pk):
company = Company.objects.get(pk=company_pk)
organization = Organization.objects.get(...)
if request.method == 'POST':
// Add company.pk and organization.pk to POST here?
// Pass data dictionary manually populated from POST and
// with company.pl and organization.pk to constructor?
contact_form = RestrictedContactForm(request.POST, request.FILES)
// Add company.pk and organization.pk to contact_form.data
// here (after making it mutable)?
if contact_form.is_valid():
contact_form.save()
return redirect(...)
return render(...)
contact_form = ContactForm(initial={'company': company, 'organizations': organization})
I have already tried every suggestion appearing in the comments above. The form simply never validates. My question hence is, what would be the correct way of doing this? Moreover, is the approach outlined at least conceptually right?
The project uses Django 1.9.
If the company and organization fields are not changeable by the user, then they should not be included in the fields list at all in RestrictedContactForm.
What you can do instead is pass the known values for organization and company into the constructor of the form, and then assign them to the object before you actually create it in the database.
class RestrictedContactForm(ContactForm):
class Meta(ContactForm.Meta):
fields = ['first_name', 'last_name', ]
def __init__(self, company, organization, *args, **kwargs):
super(RestrictedContactForm, self).__init__(*args, **kwargs)
self.company = company
self.organization = organization
def save(self, commit=True):
instance = super(RestrictedContactForm, self).save(commit=False)
if not instance.pk:
instance.company = self.company
instance.organization = self.organization
if commit:
instance.save()
return instance
def create_contact(request, company_pk):
# ...
if request.method == 'POST':
company = Company.objects.get(pk=company_pk)
organization = company.organization
contact_form = RestrictedContactForm(company, organization, request.POST, request.FILES)
# ...
# ...
I've always done this using the form_valid method. In this case, in the form_valid method of the child form:
def form_valid(self, form):
form.instance.company = foo
form.instance.organisation = bar
return super().form_valid(form)
This populates the missing field, and then saves the form.
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")
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)