I have a multiple choice field with a foreign key. I want to save which keeper was attending a training session and I want to list all keepers as a multiple choice field.
class AddAttendance(forms.ModelForm):
attendanceKeeper = Attendance.objects.only("keeper","present").all()
keeperValues = Attendance.objects.values_list("keeper__id", flat=True).distinct()
keeper = forms.ModelMultipleChoiceField(widget=forms.widgets.CheckboxSelectMultiple, queryset=Keeper.objects.filter(id__in=keeperValues, status=1))
class Meta:
model = Attendance
fields = ('keeper',)
def __init__(self, *args, **kwargs):
super(AddAttendance, self).__init__(*args, **kwargs)
self.initial["keeper"] = Keeper.objects.all()
However my problem is, I am not familiar how to handle a queryset in the view and how to loop through it and to save every instance with the value True or False.
I always get the value error that a queryset cannot be assigned
"Attendance.keeper" must be a "Keeper" instance
Can you help me how I access the queryset values and save them
def new_attendance(request, team_pk, package_pk):
if request.method == "POST":
form = AddAttendance(request.POST)
if form.is_valid():
for item in form:
attendance = item.save(commit=False)
attendance.keeper = get_object_or_404(AddAttendance.keeper)
attendance.team = get_object_or_404(Team, pk=team_pk)
attendance.created_date = timezone.now()
attendance.save()
return redirect(reverse('select_package', args=[package_pk, team_pk]))
else:
form = AddAttendance()
return render(request, 'attendance/new_attendance.html', {'form': form})
In the end I want to match keeper from the queryset and save True/False into the field present in my model
class Attendance(models.Model):
session = models.ForeignKey(Session)
keeper = models.ForeignKey(Keeper)
team = models.ForeignKey(Team)
present = models.BooleanField()
created_date = models.DateTimeField(default=timezone.now)
edited_date = models.DateTimeField(default=timezone.now)
You don't want a multiple choice field; you want a single choice. Only one keeper can be associated with each Attendance object.
You are doing a bunch of strange and unnecessary things here. You should remove most of this code, and use the ModelChoiceField which is the default for a ForeignKey. You don't want a checkbox widget either, since again that is for multiple choices; perhaps a radiobutton would be suitable.
class AddAttendance(forms.ModelForm):
class Meta:
model = Attendance
fields = ('keeper',)
widgets = {'keeper': forms.RadioSelect}
# remove the __init__ and the field definitions, you don't need them
...
form = AddAttendance(request.POST)
if form.is_valid():
attendance = item.save(commit=False)
attendance.team = get_object_or_404(Team, pk=team_pk)
attendance.created_date = timezone.now()
attendance.save()
return redirect(reverse('select_package', args=[package_pk, team_pk]))
There's no need to set the keeper explicitly in the view, since that's what the form is doing.
Related
I want "picking_person" to be selectable only from "members" of a Group. I ill trying some init and filters, but i cannot find solution. Profile model does not connected with Group model. Group model have two attributes which are connected to Profile:
class Group(models.Model):
members = models.ManyToManyField(
Profile, blank=True, default=Profile, related_name="members"
)
picking_person = models.ManyToManyField(
Profile, blank=True, default=Profile, related_name="picking_person"
)
forms.py:
class ChoosePersonPickingForm(ModelForm):
class Meta:
model = Group
fields = ['picking_person']
views.py:
def choose_person_to_pick_players(request, pk):
group = Group.objects.get(id=pk)
form = ChoosePersonPickingForm(instance=group)
group_members = group.members.all()
if request.method == "POST":
form = ChoosePersonPickingForm(request.POST, instance=group)
form.save()
return redirect('group', group.id)
context = {'form': form}
return render(request, "choose-picking-person.html", context)
Can you help me to find solution?
Just as an aside - are you sure you want Picking Person to be ManyToMany, is there more than one in a group?
Anyhow - as the list of pickable persons may be different for each form, you want to use the init function in your form to generate the options as it is called when the form instantiates. You can use the instance you are already passing in to help with the queryset. Obviously this will only work for an existing group.
class ChoosePersonPickingForm(ModelForm):
picking_person_choices= None
picking_person = forms.ModelMultipleChoiceField(label='Pick Person', queryset=picking_person_choices, required=True)
#could be a ModelChoiceField if picking_person not actually ManyToMany
class Meta:
model = Group
fields = ['picking_person']
def __init__(self, *args, **kwargs):
super(ChoosePersonPickingForm, self).__init__(*args, **kwargs)
self.picking_people_choices= Profile.objects.filter(members = self.instance)
self.fields['picking_person'].queryset = self.picking_people_choices
i'm trying to overwrite save method in my forms.py ,i have to prevent from creating duplicated objects , and if the object exists only update some fields
class Item(models.Model):
item = models.ForeignKey(Product,on_delete=models.CASCADE)
quantity = models.IntegerField()
for example if i entered this data before : item = XYZ , quantity = 100 i want to prevent from creating another XYZ item , i want to just update the quantity , for example i'll enter this data item = XYZ , quantity = 200 i try to prevent from creating this duplicate data , i just try to update the quantity previous quantity + new quantity 100 + 200 = 300 i must update the quantity to 300 for that purpose i overwrite save() in my forms.py
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ['item','quantity']
def save(self,*args,**kwargs):
if self.instance.item is None: #i also tried this if not self.instance.item
return super().save(*args,**kwargs)
else:
Item.objects.filter(item__name=self.instance.item).update(
quantity=F('quantity') + self.instance.quantity)
my views.py
def createNewProduct(request):
form = ItemForm()
if request.method == 'POST':
form = ItemForm(request.POST)
if form.is_valid():
form.save()
return render(request,'temp/add_item.html',{'form':form})
but it only update if it exists if not exists it doesn't create any new object , iexpect to create new object if it didn't exists , isn't there any way to achieve it please ? or i didn't something wrong ?
This is How I usually overwrite save method in model form:
def save(self, commit=True):
# your logic or Save your object for example:
obj = Model.objects.create(...)
return obj
Or you can also do this:
def save(self, commit=True):
obj = super().save(commit=False)
# do you logic here for example:
obj.field = something
if commit:
# Saving your obj
obj.save()
return obj
According to the documentation for ModelForm.save():
A subclass of ModelForm can accept an existing model instance as the
keyword argument instance; if this is supplied, save() will update
that instance. If it’s not supplied, save() will create a new instance
of the specified model.
This means that in your createNewProduct view, when handling POST requests, you need to check whether an Item already exists in the database and if so pass it to the Form constructor for editing, otherwise instantiate the ModelForm as per usual to create a new Item. So actually there's no need to override the ModelForm's save method
Since you want to add the old and new quantities instead of overwriting them you need to take care of that before the form is saved. This should typically happen in the form's clean method.
The resulting ItemForm and createNewProduct view would then look like this:
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ['item','quantity']
def clean(self):
cleaned_data = super().clean()
# if this Item already exists
if self.instance:
# add the old quantity to the new quantity
cleaned_data['quantity'] += self.instance.quantity
return cleaned_data
def createNewProduct(request):
if request.method == 'POST':
try:
dbItem = Item.objects.get(item=request.POST['item'])
except Item.DoesNotExist:
# get form for new Item
form = ItemForm(request.POST)
else:
# get form for existing Item
form = ItemForm(request.POST,instance=dbItem)
finally:
if form.is_valid():
form.save()
return redirect('success') # redirect on success
return redirect('failure') #redirect on failure
else:
form = ItemForm()
return render(request,'temp/add_item.html',{'form':form})
I want to set the item in dropdown using the query in the form. I want to add employee and the select company which using filter Is_Del= 0. I do not know how to set values for the drop down and where to write this query.
I tried to put in Forms.py, but it is not working.
This is form.py
class EmployeeCreateForm(forms.ModelForm):
class Meta:
model = Employee
fields = ('Emp_Name','Emp_company','Emp_Dept','Emp_Join_Date', 'Emp_End_Date')
def clean(self):
cleaned_data = super(EmployeeCreateForm, self).clean()
Emp_Name = cleaned_data.get('Emp_Name')
Emp_company = cleaned_data.get('Emp_company')
Emp_Dept = cleaned_data.get('Emp_Dept')
Emp_Join_Date = cleaned_data.get('Emp_Join_Date')
Emp_End_Date = cleaned_data.get('Emp_End_Date')
return cleaned_data
def __init__(self, *args, **kwargs):
super(EmployeeCreateForm,self).__init__(*args, **kwargs)
self.fields['Emp_company'].queryset = Company.objects.filter(Is_Del=0)
and below is my view.py
class EmployeeCraeteView(LoginRequiredMixin,SuccessMessageMixin,CreateView):
model=Employee
form = EmployeeCreateForm
success_message = " Employee Craeted successfully!"
success_url="../../company/all-companies"
template_name = 'employee_form.html'
fields =[
'Emp_Name','Emp_company','Emp_Dept','Emp_Join_Date',
'Emp_End_Date'
]
companies= Company.objects.filter(Is_Del=0)
def form_valid(self,form):
form.instance.Emp_Crt_By = self.request.user
if form.cleaned_data['Emp_Join_Date'] >= form.cleaned_data['Emp_End_Date']:
form.add_error('Emp_End_Date', 'Joining date should be less than Ending date')
return self.form_invalid(form)
return super(EmployeeCraeteView, self).form_valid(form)
I want to show only this companies in the form which are filtered by Is_Del =0
Your EmployeeCreateView is wrong:
Remove the attributes form, fields and companies
Add form_class = EmployeeCreateForm.
The reason is that form doesn't do anything in a CreateView (see here). To use a custom form class, you need to pass it to form_class.
Your CreateView was dynamically creating the form using a modelform_factory with the fields you defined (if you hadn't added those you'd have seen your mistake immediately) and so your EmployeeCreateForm is never instantiated.
I'm still learning Django. I have a wizard like form workflow where each form is filling out information in succession.
I have a model form that represents what I want inputted from the form:
Models.py
class AccountParameters(models.Model):
acctFilterName = models.ForeignKey(AccountFilters)
excludeClassification = models.ManyToManyField(ClassificationNames)
tradingCash = models.FloatField()
Forms.py
This is a dumbed down form and doesn't represent the real implementation. It was for testing.
class AccountSelectionForm(forms.ModelForm):
acctFilterName = forms.ModelChoiceField(queryset=AccountFilters.objects.all().values_list('acctFilterName', flat=True),
label="Account Filters:",
empty_label="Select Here..."
)
excludeClassification = forms.ModelMultipleChoiceField(queryset=ClassificationNames.objects.all().values_list('classificationName', flat=True),
label="Classifications Exclusion:"
)
tradingCash = forms.IntegerField(label="Remove accounts whose trading cash < % of AUM")
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}
views.py
def accountSelections(request): # NewRebalnce 2: AccountParameters with Accounts and Trading Form
if request.method == "POST":
form = AccountSelectionForm(request.POST)
if form.is_valid():
accountParameters = AccountParameters
#tradingCash = form.cleaned_data['tradingCash']
return render(request, 'NewRebalance_3.html', {'model_selection_form': ModelSelectionForm()})
else:
form = AccountSelectionForm()
return render(request, 'NewRebalance2.html', {'account_selections_form': form})
I'm not sure that I'm using Modelforms correctly. What I needed was a way to create a select drop down for my acctFilterName so I created the query set manually.
When I save the form it's not valid and in the form cleaned data I get the following:
Notice that the cleaned data only has the tradingCash field.
What am I doing wrong? Is there a better way to do this? Why is the Form in valid?
try to remove .values_list('acctFilterName', flat=True) from the ModelChoiceField and remove .values_list('classificationName', flat=True) from the ModelMultipleChoiceField.
They should be like this:
acctFilterName = forms.ModelChoiceField(
queryset=AccountFilters.objects.all(),
label="Account Filters:",
empty_label="Select Here...")
excludeClassification = forms.ModelMultipleChoiceField(
queryset=ClassificationNames.objects.all(),
label="Classifications Exclusion:")
.values_list will strip your queryset of all the data the ModelChoiceField needs to recognize the item, leaving only the model fields you specify as an argument. Namely, what you're removing here is the primary key of the model which is fundamental.
Why are you redeclaring the fields on your AccountSelectionForm ModelForm???
Better this way:
class AccountSelectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['excludeClassification'].queryset = ClassificationNames.objects.all().values_list('classificationName', flat=True)
self.fields['acctFilterName'].queryset = AccountFilters.objects.all().values_list('acctFilterName', flat=True)
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}
I am creating an app, where I am storing employee's complete information, now the problem with my development is that I am entering dependents of the employee in a manner that the Person which he adds as a dependent gets a entry in the Person model.
Dependent and DependentRelationship Model Look Like:
class Dependent(Person):
"""Dependent models: dependents of employee"""
occupation = models.CharField(_('occupation'), max_length=50, null=True,
blank=True)
self_dependent = models.BooleanField(_('self dependent'))
class DependentRelation(models.Model):
"""Dependent Relation Model for Employee"""
employee = models.ForeignKey(Employee, verbose_name=_('employee'))
dependent = models.ForeignKey(Dependent, verbose_name=_('dependent'))
relationship = models.CharField(_('relationship with employee'),
max_length=50)
class Meta:
ordering = ('employee', 'dependent',)
unique_together = ('employee', 'dependent' )
I am using a ModelForm to enter the data for the dependent this is the form for adding dependent:
class DependentForm(forms.ModelForm):
relationship = forms.CharField(_('relationship')) # TODO: max_length??
class Meta:
model = Dependent
I wanted to show all the Dependent's Information as well as the relationship with the employee, in the edit form. So is there a possible view.
Any suggestions or links can help me a lot.......
Thanks in Advance.....................
#login_required
def edit_dependents(request, id):
employee = request.user.get_profile()
try:
dependent = employee.dependent.get(id=id)
except Dependent.DoesNotExist:
messages.error(request, "You can't edit this dependent(id: %s)." %id)
return HttpResponseRedirect(reverse('core_show_dependent_details'))
dependent_relation = DependentRelation.objects.get(dependent=dependent, employee=employee)
if request.method == "POST":
form = DependentForm(data=request.POST, instance=dependent)
if form.is_valid():
dependent = form.save(commit=False)
dependent_relation = DependentRelation.objects.get(dependent=dependent, employee=employee)
dependent_relation.relationship = form.cleaned_data['relationship']
try:
dependent_relation.full_clean()
except ValidationError, e:
form = DependentForm(data=request.POST)
dependent.save()
dependent_relation.save()
return HttpResponseRedirect(reverse('core_show_dependent_details'))
else:
form = DependentForm(instance=dependent,
initial={'relationship': dependent_relation.relationship})
dictionary = {'form':form,'title':'Edit Dependents',}
return render_to_response('core/create_edit_form.html',dictionary, context_instance = RequestContext(request))
As I have defined my model form in my question, I created an edit form from the same with passing two arguments one is the instance of the dependent person with the query as
dependent = employee.dependent.get(id = id)
where the second id is the dependent's id.
Secondly I saved the relationship in the DependentRelationship model with all its attributes, having the value of relationship, and dependent from the ModelForm.
So in this way I was able to create the edit form for my app. After a long search which is working good.