How to pass a value from the view to a ModelForm - django

I'm trying to get the Id to filter items to show.
After several tutorials and docs, I'm still not get through...
Is it possible to do it ?
Here is the form:
class MakeChecklistDone(forms.ModelForm):
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
#title = forms.CharField(max_length = 32)
choices = forms.ModelMultipleChoiceField(
widget = forms.CheckboxSelectMultiple(),
queryset=CheckUpList.objects.all().filter(done=False, task=???)
)
class Meta:
model = CheckUpList
fields = ['choices', ]
I'm using the bellow view :
def task_detail(request, pk):
template_name = 'task/task-detail.html'
task = Task.objects.get(pk=pk)
...
if request.method == 'POST':
...
else:
form_checkUpList = MakeChecklistDone(request.POST, initial={'task': 11 })
But it seems I'm doing something wrong...
Any helps will be marvellous.

Instead of using a view function using a view class (Create view, update view, listing v) and use the get_form_kwargs method to pass a value to the form like below:
class task_detail(LoginRequiredMixin,
UpdateView):
template_name = 'learningcenters/lc/form.html'
form_class = LearningCenterForm
queryset = CheckUpList.objects.all()
def get_object(self):
id_ = self.kwargs.get("pk")
return get_object_or_404(task_detail, id=id_)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['task'] = 11
return kwargs
In form in init:
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
choices = forms.ModelMultipleChoiceField(
widget = forms.CheckboxSelectMultiple(),
queryset=CheckUpList.objects.all().filter(done=False, task=task)
)

ok, Thanks Salma. I made a confusion between "CBV" and "View function".
def task_detail(request, pk):
template_name = 'task/task-detail.html'
task = Task.objects.get(pk=pk)
..
if request.method == 'POST':
...
else:
form_checkUpList = MakeChecklistDone(task=task, request.POST)
For the form:
class MakeChecklistDone(forms.ModelForm):
choices = forms.ModelMultipleChoiceField(widget = forms.CheckboxSelectMultiple(), queryset=None)
class Meta:
model = CheckUpList
fields = ['choices', ]
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
self.fields['choices'].queryset = CheckUpList.objects.all().filter(done=False, task=task))

Related

request not defined inside forms.py class (forms.Form)

The error
NameError: name 'request' is not defined
My forms.py
class PersonForm(forms.Form):
name = forms.CharField(required=False)
job_title = forms.CharField(required=False)
status = forms.TypedChoiceField(choices=Person.STATUS_CHOICES)
project = Project.objects.get(users=request.user, pk=self.kwargs.get('pk'))
company = forms.ModelChoiceField(queryset=project.companies.all(),required=False)
new_company = forms.CharField(required=False)
note = forms.CharField(required=False)
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
def clean(self):
return self.cleaned_data
views.py
class PersonCreate(LoginRequiredMixin, FormView):
template_name = 'person/person_form.html'
form_class = PersonForm
success_url = '/project/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
cleaned_data = form.clean()
active_project = self.request.session['active_project']
project = Project.objects.get(users=self.request.user, pk=self.request.session['active_project'])
if cleaned_data['name']:
person, created = Person.objects.get_or_create(
name=cleaned_data['name'],
job_title=cleaned_data['job_title'],
created_by=self.request.user,
status=cleaned_data['status'],
project=project
)
if cleaned_data['new_company']:
company, created = Company.objects.get_or_create(name=cleaned_data['new_company'], project=project, created_by=self.request.user)
company.persons.add(person)
company.save()
if cleaned_data['note']:
person.note_set.create(content=cleaned_data['note'], created_by=self.request.user)
person.save()
if cleaned_data['company']:
company = project.companies.get(name=cleaned_data['company'])
company.persons.add(person)
company.save()
return super().form_valid(form)
def get_success_url(self):
return self.request.POST.get('next', '/project/' + str(self.request.session['active_project']))
I want to filter the queryset on the forms.ModelChoiceField field company. Based on the companies of the project the user has access to. How would I do that? Can I access request.session data as well here?
You can't do that like this, because Django forms don't have access to the request at all.
So the best approach I can think of is to pass the user to the form and then use the data when initialized.
First you have to pass the user and pk in the view.
views.py:
# ...
form = PersonForm(user=request.user, pk=kwargs.get('pk'))
Then in your form, you can catch both kwargs and update the project with the correct value,
class PersonForm(forms.Form):
# your form fields code ...
def __init__(self, *args, **kwargs):
# get the user and pk
user = kwargs.pop('user', None)
pk = kwargs.pop('pk', None)
# update project field
super(PersonForm, self).__init__(*args, **kwargs)
self.fields['project'] = Project.objects.get(users=user, pk=pk)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
In class-based views to update Form kwargs:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({"request": self.request})
return kwargs

Django add value to hidden field inline formset

I am using Django 1.11. I am trying to add a value to a hidden field in an inline formset form. I have tried unsuccessfully inserting the hidden field value at various points of def get_context_data and def form_valid. The code I am using is as follows:
views.py
#method_decorator(login_required, name='dispatch')
class DocumentCreate(CreateView):
model = DocumentClient
success_url = reverse_lazy('documents')
form_class = DocumentForm
def get_context_data(self, **kwargs):
data = super(DocumentCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['docform'] = DocumentFormSet(self.request.POST, self.request.FILES)
else:
data['docform'] = DocumentFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
docform = context['docform']
if docform.is_valid():
self.object = form.save()
docform.instance = self.object
docform.save()
return HttpResponseRedirect('documents')
else:
return self.render_to_response(self.get_context_data(form=form))
forms.py
class DocumentForm(ModelForm):
class Meta:
model = DocumentClient
exclude = ()
widgets = {
'cnum': HiddenInput(),
}
def __init__(self, *args, **kwargs):
super(DocumentForm, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields['cnum'].required = False
class DocumentDetailForm(ModelForm):
class Meta:
model = DocumentDetail
exclude = ()
widgets = {
'document_date': DateInput(),
}
def __init__(self, *args, **kwargs):
super(DocumentDetailForm, self).__init__(*args, **kwargs)
self.fields['document_description'].required = False
DocumentFormSet = inlineformset_factory(DocumentClient, DocumentDetail, form=DocumentDetailForm, extra=10, can_delete=False)
The hidden field 'cnum' is that what I am trying to insert a value for capturing in the model. Is anyone able to provide any guidance on how to acheive this? Any assistance is gratefully appreciated!
In DocumentCreate, have you tried this?
class DocumentCreate(CreateView):
def get_initial(self):
# Get initial value from kwargs (If needed) and save as instance variable.
self.cnum_val = self.kwargs.get('cnum_value')
def form_valid(self, form):
# Insert your desired value to cnum (or you can simply forget get_initial and supply whatever value here)
form.instance.cnum = self.cnum_val
self.object = form.save()
...
self.render_to_response(self.get_context_data(form=form))
form.instance refers to the unsaved model object used by the form
See here also.

How do I filter values in Django CreateView, UpdateView

I am trying to use CreateView and UpdateView to modify records. My problem is that the ForeignKey dropdown lists values (Psa.number) for all companies instead only those of the company to which the user belongs.
class Psa(models.Model):
owner = models.ForeignKey(Employer)
number = models.PositiveIntegerField(unique=True...
type = models.CharField(max_length=6 ...
class Employer(models.Model):
employer_name = models.CharField(max_length=100, unique=True)
The form:
class PsaCreateForm(forms.ModelForm):
class Meta:
model = Psa
fields = [
'number',
'type',
]
What is the best way to solve this? I've got several other conditions that use the same company foreignkey relationship so is there a way to create a method on the model that I can reuse?
You need get_form_kwargs(self) in CreateView and UpdateView:
forms.py:
class PsaCreateForm(forms.ModelForm):
model = Psa
fields = [
'number',
'type',
]
def __init__(self, *args, **kwargs):
self.current_user = kwargs.pop('user')
super(PsaCreateForm, self).__init__(*args, **kwargs)
if self.current_user:
self.fields['number'].queryset = Psa.objects.filter(owner=self.current_user)
views.py
class PsaCreate(CreateView):
model = Psa
template_name = 'form.html'
form_class = PsaCreateFrom
def get_form_kwargs(self):
kwargs = super(PsaCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Also a good idea. Set def dispatch(self, request, *args, **kwargs): in your Views.
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.owner != self.request.user:
return HttpResponseRedirect(reverse('home'))
return super(PsaUpdate, self).dispatch(request, *args, **kwargs)

django form queryset filter by current user

I have made a search form like this where user can filter the news accroding to published date and the crawlers that they have selected previously.. Here is my form
class SearchForm(forms.Form):
pub_date_from = forms.CharField(label="From",max_length=20)
pub_date_to = forms.CharField(label="To",max_length=30)
crawler = forms.ModelMultipleChoiceField(label="Crawler",queryset=Crawler.objects.filter(created_by=self.request.user)
Here I want the crawler to be shown only the user have selected previously..
Here is my view..
class SingleNewsView(ListView):
model = News
form_class = SearchForm
template_name = "single_news.html"
# def post(self, request, **kwargs):
# print "request"
# form = SearchForm(request.user)
def get(self, request, pk, **kwargs):
#form = SearchForm(request.user)
self.pk = pk
self.pub_from = request.GET.get('pub_date_from',False)
self.pub_to = request.GET.get('pub_date_to',False)
self.crawlers = request.GET.get('crawler',False)
self.format = request.GET.get('format',False)
print self.format
print self.crawlers
return super(SingleNewsView,self).get(request,pk, **kwargs)
def get_context_data(self, **kwargs):
context = super(SingleNewsView,self).get_context_data(**kwargs)
context["form"] = SearchForm
if self.pub_from and self.pub_to and self.crawlers:
qs = News.objects.filter(category_id=self.pk).filter(published_date__range=(self.pub_from,self.pub_to), crawler=self.crawlers)
else:
qs = News.objects.filter(category_id=self.pk)
context["something"] = qs
self.request.session['something_pks'] = [ i.details for i in qs ]
return context
How can I get the current user in form and filter according to current user.. Need help
Just pass the user to form in view as keyword argument.
Just don't pass it on in form init method. Check out this post:
Passing **kwargs to Django Form
you hand over request.user just like user_details are passed into form in that example.
# Your best option is to declare the variable before `__init__`,
# and then set the variable to a form field inside `__init__`:
from django import forms
class MyForm(forms.Form):
location = None
def __init__(self, *args, **kwargs):
self.location = forms.ChoiceField(choices=Locations.objects.filter(user=kwargs.pop('user', None)))
super(MyForm, self).__init__(*args, **kwargs)
# In your class-based view pass self.request.user
# or in a function-based view pass request.user:
def MyView(request)
MyForm(user=request.user)

User current user on new Django class views forms

I am using the django 1.3 on trunk, and start learning about class views.
I had this:
class Project(models.Model):
title = models.CharField(max_length=90)
slug = models.CharField(max_length=90)
description = models.TextField()
owner = models.ForeignKey(User)
class ProjectForm(ModelForm):
class Meta:
model = Project
exclude = ('owner',)
widgets = {
'description': Textarea(attrs={'cols': 40, 'rows': 20}),
}
class ProjectCreateView(CreateView):
model = Project
form_class = ProjectForm
def get(self, request, *args, **kwargs):
return super(ProjectCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super(ProjectCreateView, self).post(request, *args, **kwargs)
I am trying, to get a form using model forms from django excluding the owner field, to get the field value after with the request.user property.
The form as it is, works. But how can make sure the ModelForm use request.user for the Project.owner field?
My first guess, was to override get_form_kwargs method from the view
class ProjectCreateView(CreateView):
# .....
def get_form_kwargs(self, **kwargs):
self.initial['owner': self.request.user})
kwargs = super(ProjectCreateView, self).get_form_kwargs(**kwargs)
return kwargs
But seem to have no effect on the data used by the model form
get_form_kwargs is supposed to return a dict of arguments for your form - you set self.initial, but you didn't attach it to kwargs:
def get_form_kwargs(self, **kwargs):
kwargs = super(ProjectCreateView, self).get_form_kwargs(**kwargs)
kwargs['initial']['owner'] = self.request.user
return kwargs