I'm trying to create a modelform to allow users to change their username. I'm trying to do this using FormView instead of UpdateView because I want to include other forms (user management functionality) in this view eventually.
Relevant forms.py:
class FormHorizontalModelForm(forms.ModelForm)
def __init__(self, *args, **kwargs):
super(FormHorizontalModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
class PlayerRenameForm(FormHorizontalModelForm):
def __init__(self, user, *args, **kwargs):
super(PlayerRenameForm, self).__init__(*args, **kwargs)
self.helper.add_input(Submit('change_username', 'Change Username'))
class Meta:
model = User
fields = ('username',)
def save(self):
pass # I figured this might be saving the object since this is inherited off ModelForm
def form_valid(self, form):
self.change_username(new_username = self.cleaned_data['username'])
# self.send_email(new_username = self.cleaned_data['username'])
def change_username(self, new_username):
player = Player.objects.get(user = self.instance)
self.instance.username = new_username
self.instance.save()
player.changed_username = True
player.save()
views.py
class AccountView(UserAuthenticationMixin, FormView):
template_name = 'game/profile.html'
success_url = '/accounts/'
form_class = PlayerRenameForm
form_class_two = CrispyPasswordSetForm
form_class_three = CrispyPasswordChangeForm
def get_context_data(self, **kwargs):
context = super(AccountView, self).get_context_data(**kwargs)
if 'form' not in context:
context['form'] = self.form_class(user = self.request.user, data = (self.request.POST or None))
if 'password_set_form' not in context:
context['password_set_form'] = self.form_class_two(user = self.request.user, data = (self.request.POST or None))
if 'password_change_form' not in context:
context['password_change_form'] = self.form_class_three(user = self.request.user, data = (self.request.POST or None))
return context
def form_invalid(self, **kwargs):
return self.render_to_response(self.get_context_data(**kwargs))
def get_form(self, form_class):
return form_class(user = self.request.user, **self.get_form_kwargs())
def post(self, request, *args, **kwargs):
if 'change_username' in request.POST:
form = self.form_class(user = request.user, instance = request.user, data = self.request.POST)
form_name = 'form'
elif 'set_password' in request.POST:
form = self.form_class_two(user = request.user, data = self.request.POST)
form_name = 'password_set_form'
elif 'change_password' in request.POST:
form = self.form_class_three(user = request.user, data = self.request.POST)
form_name = 'password_change_form'
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(**{form_name: form})
The form returns valid, and returns to success_url. I know for a fact that it is passing into the correct part of the post function since I have stripped away the other parts to ensure that was working.
Related
I am trying to pass the request object into my inlineformset_factory and am struggling to accomplish this.
In forms.py I have the following:
class SummativeScoreForm(forms.ModelForm):
"""
Form definition for SummativeScore Form
"""
subdomain_proficiency_level = forms.ModelChoiceField(
empty_label="Undecided",
queryset=SubdomainProficiencyLevel.objects.none(),
widget=forms.RadioSelect,
required=False,
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request", None)
super(SummativeScoreForm, self).__init__(*args, **kwargs)
if self.instance:
if self.request.user == self.instance.summative.employee:
self.fields["subdomain_proficiency_level"].disabled = True
self.fields[
"subdomain_proficiency_level"
].queryset = SubdomainProficiencyLevel.objects.filter(
subdomain=self.instance.subdomain
)
self.fields[
"subdomain_proficiency_level"
].label = f"""
{self.instance.subdomain.character_code}:
{self.instance.subdomain.short_description}
"""
class Meta:
model = SummativeScore
fields = "__all__"
widgets = {
"subdomain_proficiency_level": forms.RadioSelect(
attrs={"class": "list-unstyled"}
),
}
SummativeScoreInlineFormset = inlineformset_factory(
Summative,
SummativeScore,
fields=("subdomain_proficiency_level",),
can_delete=False,
extra=0,
form=SummativeScoreForm,
)
I'm using a FormView CBV to show this inline_formset
class SummativeScoreFormView(
LoginRequiredMixin,
UserIsObserverOrObserveeMixin,
SingleObjectMixin,
FormView,
):
model = Summative
template_name = "commonground/summative_score_form.html"
pk_url_kwarg = "summative_id"
def get(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().get(request, *args, **kwargs)
def get_form(self, form_class=None):
return SummativeScoreInlineFormset(
**self.get_form_kwargs(), instance=self.object
)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["request"] = self.request
return kwargs
def form_valid(self, form):
form.save()
messages.add_message(messages.SUCCESS, "Changes were saved!")
HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form):
print("invalid form")
return super().form_invalid(form)
def get_success_url(self):
user_id = self.kwargs["user_id"]
summative_id = self.kwargs["summative_id"]
return reverse(
"commonground:summative_detail",
kwargs={
"user_id": user_id,
"summative_id": summative_id,
},
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
summative = get_object_or_404(
Summative, pk=self.kwargs["summative_id"]
)
context["summative"] = summative
return context
I keep getting this error:
__init__() got an unexpected keyword argument 'request'
I'm not sure how best to resolve this - any ideas? Is there a clear way to pass the request to the inlineformset_factory?
You are passing the request to the formset and not to the forms in the formset, hence you get the error. For passing custom parameters to the formsets forms [Django docs] you need to pass a form_kwargs parameter to the formset:
class SummativeScoreFormView(
LoginRequiredMixin,
UserIsObserverOrObserveeMixin,
SingleObjectMixin,
FormView,
):
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['form_kwargs'] = {'request': self.request}
return kwargs
In my detailView I have 2 methods get_context_data and post. In get_context_data I can get the detailView pk with self.object.pk but how can I get it in the post method?
[ updated ]
here is the view
class Class_detailView(LoginRequiredMixin, DetailView):
login_url = '/'
model = Class
template_name = "attendance/content/teacher/class_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['attendance_form'] = AttendanceForm(current_class_pk=self.object.pk) # pass data to form via kwargs
return context
def post(self, request, *args, **kwargs):
if request.method == "POST":
attendance_form = AttendanceForm(request.POST)
if attendance_form.is_valid():
attendance_form.instance.teacher = self.request.user
attendance_form.save()
return redirect('class-detail', pk=self.kwargs.get('pk'))
form
class AttendanceForm(forms.ModelForm):
class Meta:
model = Attendance
fields = ['student',]
def __init__(self, *args, **kwargs):
current_class_pk = kwargs.pop('current_class_pk')
super(AttendanceForm, self).__init__(*args, **kwargs)
current_student = Class.objects.get(id=current_class_pk)
self.fields['student'].queryset = current_student.student
I want to get the pk and pass it to the form when the post request is called.
How can I do it?
did you try this:
def post(self, request, *args, **kwargs):
if request.method == "POST":
attendance_form = AttendanceForm(request.POST, current_class_pk=self.kwargs.get('pk'))
if attendance_form.is_valid():
attendance_form.instance.teacher = self.request.user
attendance_form.save()
return redirect('class-detail', pk=self.kwargs.get('pk'))
Want to have Django From dropdown filtered by logged-in User (Customer), using __init__ method. But when submit the form, keep having this Field id expected a number but got <QueryDict: { error:
class OrderForm(ModelForm):
class Meta:
model = Order
fields = ['contract', 'quantity', 'status']
def __init__(self, customer, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['contract'].queryset = Contract.objects.filter(customer=customer)
#login_required(login_url='login')
def createOrder(request):
customer = request.user.customer.id
form = OrderForm(customer)
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.customer = request.user.customer
form.save()
messages.success(request, 'Ticket submitted successfully .')
return redirect('customer_table')
context = {'form':form}
return render(request, 'create-order.html', context)
you can pass any attribute in form like this
in view:
form = OrderForm(request.POST, customer=request.user)
in form:
def __init__(self, *args, **kwargs):
customer = kwargs.pop('user') # allway before super()
# and call .pop() not .get() on kwargs, for upper class not evaluate user keyword
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['contract'].queryset = Contract.objects.filter(customer=customer)
I summarize the working solutions as below:
View.py
def createOrder(request):
form = OrderForm(request.POST, customer=request.user.customer.id)
if request.method == 'POST':
form = OrderForm(request.POST, customer=request.user.customer.id)
if form.is_valid():
form = form.save(commit=False)
form.customer = request.user.customer
form.save()
messages.success(request, 'Ticket submitted successfully .')
return redirect('customer_table')
context = {'form':form}
return render(request, 'create-order.html', context)
class OrderForm(ModelForm):
class Meta:
model = Order
fields = ['contract', 'quantity', 'status']
def __init__(self, *args, **kwargs):
customer = kwargs.pop('customer')
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['contract'].queryset = Contract.objects.filter(customer__id=customer)
class PreChildrenView(CreateView):
model = PreDealDetails2
template_name = 'cam_app/children_form.html'
fields = '__all__'
success_url = reverse_lazy('forms_app:deal-entering')
session_initial = 'children_'
def get_initial(self,**kwargs):
initial = super(PreChildrenView, self).get_initial(**kwargs)
initial['deal_id'] = self.request.session['deal_id']
return initial
def get_context_data(self, **kwargs):
data = super(PreChildrenView, self).get_context_data(**kwargs)
if self.request.POST:
data['childrens'] = ChildrenFormSet(self.request.POST)
print('post')
else:
print('get')
data['childrens'] = ChildrenFormSet()
data['childrens'].extra = 5
data['info'] = 'Children Details'
return data
def form_valid(self, form):
print('wwwww')
context = self.get_context_data()
childrens = context['childrens']
if form.is_valid():
pass
if childrens.is_valid():
count = 0
self.object = form.save()
childrens.instance = self.object
childrens.save()
self.request.session[self.session_initial + 'children_count'] = count
self.request.session['valid_children'] = True
messages.success(self.request, 'Successfully filled Children Details')
return self.render_to_response(self.get_context_data(form=form))
else:
return super(PreChildrenView, self).form_invalid(form)
class UpdatePreChildrenView(UpdateView):
model = PreDealDetails2
template_name = 'cam_app/children_form.html'
fields = '__all__'
success_url = reverse_lazy('forms_app:deal-entering')
session_initial = 'children_'
def get_object(self, queryset=None):
return PreDealDetails2(deal_id = self.request.session['deal_id'])
def get_context_data(self, **kwargs):
data = super(UpdatePreChildrenView, self).get_context_data(**kwargs)
if self.request.POST:
a = PreDealDetails2.objects.get(deal_id = self.request.session['deal_id'])
data['childrens'] = ChildrenFormSet(self.request.POST)
print('post')
else:
print('get')
data['childrens'] = ChildrenFormSet(instance=self.object)
data['childrens'].extra = 5
data['info'] = 'Children Details'
return data
def form_valid(self, form):
print('update valid')
context = self.get_context_data()
childrens = context['childrens']
if form.is_valid():
print('wejri')
self.object =form.save()
if childrens.is_valid():
childrens.instance = self.object
childrens.save()
count = 0
self.request.session[self.session_initial + 'children_count'] = count
self.request.session['valid_children'] = True
messages.success(self.request, 'Successfully filled Children Details')
return self.render_to_response(self.get_context_data(form=form))
else:
return super(UpdatePreChildrenView, self).form_invalid(form)
else:
print('sfeief')
class PreChildrenRedirectView(RedirectView):
def get_redirect_url(self):
flag = 0
try:
PreDealDetails2.objects.get(deal_id=self.request.session['deal_id'])
flag = 1
except:
pass
if flag == 1:
return reverse("cam_app:update-prechildren-view")
else:
return reverse("cam_app:create-prechildren-view")
I am using above code to enter details to form and later update form.
CreateView is working fine and saving data.
UpdateView is displaying data. When i try to save updateview it is showing following error :-
Code Flow :-
First PreChildrenRedirectView is called. It checks if data already exist or not. If it does then Updateview is called and if it doesnot exist then Createview is called.
I am not using slug. Instead i am using get_object in Updateview. Let me know what is causing problem or how to solve the error.
Update
I have changed the forms.py to remove the error in child. But Deal Id is still showing error. I am also attaching the forms.py below
class ChildrenForm(forms.ModelForm):
class Meta:
model = PreChildrenDetails
fields = '__all__'
def __init__(self, *args, **kwargs):
super(ChildrenForm, self).__init__(*args, **kwargs)
self.fields['deal_id'].widget.attrs['readonly'] = True
self.helper = FormHelper(self)
self.helper.form_show_labels = False
def clean(self):
print('wow')
pass
ChildrenFormSet = inlineformset_factory(PreDealDetails2,PreChildrenDetails, form=ChildrenForm, fields = '__all__', extra=1)
Below is screenshot of error after updating
I'm fairly new to python and have been searching for awhile to find how I can edit form data BEFORE all the standard python form/field validators do their magic.
I have a model form with an IntegerField which I'd like to remove the "$" and commas from (using some sort of custom validation), then let the normal to_python() validate() etc do their thing.
My code is below - any help would be much appreciated!
forms.py
class BuyerSettingsForm(forms.ModelForm):
total_offer_limit = forms.IntegerField(required=False, max_value=10000000, min_value=0)
def __init__(self, request, *args, **kwargs):
super(BuyerSettingsForm, self).__init__(*args, **kwargs)
class Meta:
model = Buyer
fields = ['total_offer_limit']
def save(self, commit=True):
profile = super(BuyerSettingsForm, self).save(commit=commit)
profile.total_offer_limit = self.cleaned_data['total_offer_limit']
profile.save()
return profile
views.py
class SettingsPreferences(LoginRequiredMixin, BuyerAccessRequiredMixin, BuyerAdminAccessRequiredMixin, UpdateView):
template_name = 'invoicely/buyer/settings/buyer_settings.html'
form_class = BuyerSettingsForm
success_url = reverse_lazy('settings_preferences')
def get_object(self, *args, **kwargs):
return self.request.user.profile.buyer
def get_initial(self):
ctx = super(SettingsPreferences, self).get_initial()
ctx.update({
'total_offer_limit': self.object.total_offer_limit,
})
return ctx
def get_form_kwargs(self):
kwargs = super(SettingsPreferences, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def form_valid(self, form):
self.object = form.save()
messages.add_message(self.request, messages.SUCCESS, "Settings successfully updated")
return super(SettingsPreferences, self).form_valid(form)
If you are already overloaded get_form_kwargs you can do this. This is data which your form will be initialized with. So we can edit it before its initialization.
class SettingsPreferences(LoginRequiredMixin, BuyerAccessRequiredMixin, BuyerAdminAccessRequiredMixin, UpdateView):
...
def get_form_kwargs(self):
kwargs = super(SettingsPreferences, self).get_form_kwargs()
kwargs = copy.deepcopy(kwargs)
kwargs['request'] = self.request
if self.request.method in ('POST', 'PUT'):
# here put your data editing code
kwargs['data']['total_offer_limit'] = int(kwargs['data']['total_offer_limit'].strip().replace('$', ''))
return kwargs