Django Create View parameters on form - django

I have a Django generic create view
class TestCreateView(CreateView):
form_class = TestCreateForm
##forms.py
class TestCreateForm(forms.ModelForm):
class Meta:
model = Test
def __init__(self, user, *args, **kwargs):
super(TestCreateForm).__init__(*args, **kwargs)
self.fields['test_field'] = Testing.objects.filter(user=user)
In function based views I would do like this:
form = TestCreateForm(request.user)
Now on the generic class based view do I have to overwrite, get and post method just for this?

class TestCreateView(CreateView):
form_class = TestCreateForm
def get_form_kwargs(self, **kwargs):
form_kwargs = super(TestCreateView, self).get_form_kwargs(**kwargs)
form_kwargs["user"] = self.request.user
return form_kwargs

Since you need to add the argument in the init (every time you instanciate the form) what you can do is override the get_form_kwargs from the CreateView class:
class TestCreateView(CreateView):
form_class = TestCreateForm
def get_form_kwargs(self):
kwargs = {
'initial': self.get_initial(),
'prefix': self.get_prefix(),
'user': self.request.user
}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs

Related

How to pass a value from the view to a ModelForm

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))

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.

UpdateView gives blank form in django inline formset

MY CreateView worked fine but when I try to update this form data, it gives blank form. No data was shown. Here is my views.py:
#require_authenticated_permission(
'member.add_person')
class PersonCreate( FormsetMixin, CreateView):
template_name = 'member/person_form.html'
model = Person
form_class = MemberForm
formset_class = PersonFormSet
#require_authenticated_permission(
'member.change_person')
class PersonUpdate( FormsetMixin, UpdateView):
template_name = 'member/person_form.html'
model = Person
form_class = MemberForm
formset_class = PersonFormSet
Here is my formset:
class MemberForm(ModelForm):
class Meta:
model = Person
exclude = ('user',)
def __init__(self, *args, **kwargs):
super(MemberForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs['placeholder'] = 'Your full name'
self.fields['tele_land'].label = 'Land phone'
self.fields['tele_cell'].label = 'Cell phone'
self.fields['passing_year'].label = 'Passing year'
self.fields['passing_year'].help_text = 'According to your session year'
def save(self, request, commit=True):
person = super().save(commit=False)
if not person.pk:
person.user = get_user(request)
if commit:
person.save()
self.save_m2m()
return person
class ChildrenForm(ModelForm):
class Meta:
model = Children
fields = '__all__'
PersonFormSet = inlineformset_factory(Person, Children, extra=0, min_num=1, fields=('child_name', 'child_birth_date','blood_group' ))
Url:
url(r'^person/create/$', views.PersonCreate.as_view(), name='person-create'),
url(r'^person/(?P<slug>[\w\-]+)/update/$', views.PersonUpdate.as_view(), name='person-update'),
My formset mixin:
class FormsetMixin(object):
object = None
def get(self, request, *args, **kwargs):
if getattr(self, 'is_update_view', False):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
formset_class = self.get_formset_class()
formset = self.get_formset(formset_class)
return self.render_to_response(self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
if getattr(self, 'is_update_view', False):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
formset_class = self.get_formset_class()
formset = self.get_formset(formset_class)
if form.is_valid() and formset.is_valid():
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def get_formset_class(self):
return self.formset_class
def get_formset(self, formset_class):
return formset_class(**self.get_formset_kwargs())
def get_formset_kwargs(self):
kwargs = {
'instance': self.object
}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs
def form_valid(self, form, formset):
self.object = form.save(self.request)
formset.instance = self.object
formset.save()
return redirect(self.object.get_absolute_url())
def form_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
Why my UpdateView gives blank form?
Proably because getattr(self, 'is_update_view', False) always is false so you're not loading any self.object.
I have for similar situations used ModelFormSetView from django-extra-views. It's easy to use if you already understand Django class based views and will save you a lot of code to write and maintain yourself.
BTW you should implement get_queryset and prefetch the Children.
Use in UpdateView: is_update_view = True. It will be like
class PersonUpdate( FormsetMixin, UpdateView):
template_name = 'member/person_form.html'
model = Person
is_update_view = True
form_class = MemberForm
formset_class = PersonFormSet

Access request in __init__ in ModelForm

How can I access request in __init__ form?
forms.py
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self.request ...
views.py
myform = MyForm(request.POST, request=request)
but what if I use class based views FormView?
If you need to access request in your MyForm you can override the FormView.get_form_kwargs method.
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({'request': self.request})
return kwargs
FormView source
class FormMixin(ContextMixin):
...
def get_form(self, form_class=None):
"""
Returns an instance of the form to be used in this view.
"""
if form_class is None:
form_class = self.get_form_class()
return form_class(**self.get_form_kwargs())
def get_form_kwargs(self):
"""
Returns the keyword arguments for instantiating the form.
"""
kwargs = {
'initial': self.get_initial(),
'prefix': self.get_prefix(),
}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs
if form_class is None:
form_class = self.get_form_class()
return form_class(**self.get_form_kwargs())
You can use the user_passes_test decorator, documented at:
https://docs.djangoproject.com/en/1.9/topics/auth/default/#django.contrib.auth.decorators.user_passes_test
def my_test(user):
return user.username == 'me'
#user_passes_test(my_test)
class MyView(FormView):
...

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