Adding custom parameter to django modelform - django

I'm having troubles adding a custom parameter to a modelform (in this case, the currrent user from request.user)
I used to do this on previous projects, and I can't manage to make it work on a new project on Django 1.10.4.
I got this error :
TypeError at /realestateprogram/edition_appartement/19/
__init__() got an unexpected keyword argument 'user'
This is my view :
apartment = get_object_or_404(Apartment, pk=apartment_id)
if request.method == 'POST':
form = ApartmentForm(request.POST, request.FILES, instance=apartment, user=request.user)
if form.is_valid():
form.save()
return redirect('list_realestateprogram_apartment', realestateprogram_id=apartment.realestateprogram.id)
else:
print form.errors
else:
form = ApartmentForm(instance=apartment, user=request.user)
and this is my form :
class ApartmentForm(forms.ModelForm):
class Meta:
model = Apartment
exclude = ('realestateprogram',)
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(ApartmentForm, self).__init__(*args, **kwargs)
Thanks in advance if you can help me

Try to pass all the values with keyword arguments:
form = ApartmentForm(data=request.POST, files=request.FILES, instance=apartment, user=request.user)
If you look at the class based generic views, that's how they do it. I would also suggest that you look at Form handling with class-based views.

Related

How i can add correctly data to an existing choicefield and save it in database: Django

I want to add some choices to an exiting fieldchoice from the database,
I have did that in my views.py:
def operation(request):
if request.method == 'GET':
form = FormOperation(instance=request.user, )
var = Metry.objects.filter(user=request.user).last().profile.name
varr = Metry.objects.filter(user=request.user).last().profile.category
form.fields['dite'].choices.append((varr, var))
print(form.fields['dite'].choices)
else:
if request.user.is_authenticated:
form = FormOperation(request.POST, )
if form.is_valid():
form.save()
return render(request, 'pages/operation.html', {'form': form})
models.py:
dite = models.CharField(null = True, max_length=60,choices = CHOICES)
forms.py:
class FormOperation(forms.ModelForm):
class Meta:
model = Operation
exclude = ("user",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
after "append" the choice , As a test I have did a "print" to see the choice and it's normal i can see it in my terminal, but not in the page browser of my django application indeed ,i can see just the first choices without considering what i have append in my views.py,...
Any help will be appreciated.
You can use list extend method. (Make sure your CHOICES is a LIST)
new_choices[('abc', 'def'),]
CHOICES.extend(new_choices)
(Note: It will not override the existing value in select field, and will create another choice with same value)

Pass logged user to model field django

I don't know how to get the username from the current user.
I have a edit form rendered with djano-crispy-forms:
class RecepcionForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self,*args,**kwargs):
super(RecepcionForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar')
)
)
class Meta:
model = DetalleRecepcion
my views.py:
#login_required(login_url='/login/')
def RecepcionView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(request.POST, instance=r)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(instance=r)
return render_to_response('recepcion.html',
{'form':form},
context_instance=RequestContext(request))
I need to fill the field usuario with the logged username.
I tried with form = request.user.username before the save of the form.
I am confused of this have to be done passed the value in the form definition or in the view.
If is possible to overwrite the retrieved value from the database and fill the field with the username in the form class.
Another question
How can I change the widget type in the form. The field id_proveedor is a foreign key and is rendered as a drop down box (select widget), but I need to show the value displayed in a label where the can't edit the value.
I tried with the readonly propertie, but the user is not capable to write in the select box, but is capable to select from the drop down.
How can change the widget or how can I disabled the drop dwon function from the select box
Thanks in advance
You can always pass whatever arguments or keyword arguments you need to a form class, you just have to remove them from the *args or **kwargs that are passed on when calling super(), otherwise Django will throw an exception because it's receiving an arg or kwarg it's not expecting:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # notice the .pop()
super(MyForm, self).__init__(*args, **kwargs)
# views.py
def my_view(request):
# assuming the user is logged in
form = MyForm(user=request.user)
I came across the same as your problem and found a solution just now. I do not know whether this is the best solution or maybe I will have problem later.
def add_trip_event(request):
#form = Trip_EventForm()
#return render(request, 'trips/add_trip_event.html', {'form': form})
if request.method == "POST":
form = Trip_EventForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.trip_owner = Owner.objects.get(owner=request.user)
post.pub_date = timezone.now()
post.view = 0
post.save()
form.save_m2m()
return HttpResponseRedirect(reverse('trips:index'))
else:
form = Trip_EventForm()
return render(request, 'trips/add_trip_event.html', {'form': form})

Django ModelForms __init__ kwargs create and update

I'm trying to get the request.user into a ModelForm. I feel like I've tried all permutations of this from overloading the
__init__
argument (per Django form, request.post and initial) to trying to pass it as a kwargs (per Django form __init__() got multiple values for keyword argument). I
It does seem like the kwargs is the best approach but I'm totally stymied by it.
Here's the ModelForm:
class DistListForm(ModelForm):
members = ModelMultipleChoiceField(queryset=Company.objects.none())
class Meta:
model = DistList
fields = ['name', 'description', 'members', 'is_private']
def __init__(self, *args, **kwargs):
super(DistListForm, self).__init__(*args, **kwargs)
user = kwargs.pop('user', None)
up = UserProfile.objects.get(user=user)
/.. etc ../
Here's how the create function currently works:
def distlistcreate(request):
user = {'user': request.user}
form = DistListForm(**user)
if request.method == 'POST':
form = DistListForm(request.POST)
if form.is_valid():
distlist = form.save(commit=False)
distlist.creator = request.user
distlist.save()
form.save_m2m()
return HttpResponseRedirect(reverse('distlistsmy'))
return render(request, 'distlistcreate.html',{'form':form})
which throws a TypeError: init() got an unexpected keyword argument 'user'. The update method is equally unhelpful:
def distlistupdate(request, object_id):
distlist = get_object_or_404(DistList, id=object_id)
form = DistListForm(user=request.user, instance=distlist)
if request.method == 'POST':
form = DistListForm(request.POST, user=request.user)
It also throws the same error.
I've been banging my head against this wall for two hours now. What is the correct way to pass a keyword argument into a ModelForm?
This is Django 1.6.1 if that makes a difference.
You have to pop the user argument before call super() so it will no conflict wit the default arguments of ModelForm
class DistListForm(ModelForm):
members = ModelMultipleChoiceField(queryset=Company.objects.none())
class Meta:
model = DistList
fields = ['name', 'description', 'members', 'is_private']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(DistListForm, self).__init__(*args, **kwargs)
user_profile = UserProfile.objects.get(user=user)
Just did exactly this yesterday, on Django 1.5, and I am able to do:
def __init__(self, user, *args, **kwargs):
on my ModelForm. Then I just use user without having to pop it from the kwargs.

Django: Cleaning and validating FORMS that depend on each other

The django docs cover cleaning and validating FIELDS that depend on each other, but I can't find anything that covers forms that depend on each other.
I have a single HTML form with which contains both a standard django form and a django formset. Proper validation of each form in the formset is entirely conditional based on a value from the main form (e.g. check a box on the main form, and a specific field on each form in the formset suddenly becomes required).
My intuition is to "simply" pass the entire main form into the formset validation call, like so:
def my_view(request):
MyFormSet = formset_factory(MyForm, extra=2, can_order=True)
if request.method == 'POST':
form = MainForm(request.POST)
formset = MyFormSet(request.POST)
if form.is_valid() and formset.is_valid(form): # <-- ?!?!
# The formset is now validated based on the form
However, to make that work, I believe I would have to override both the formset is_valid() along with the underlying form is_valid() and clean() method. So, it gets pretty messy pretty quick.
Is there a better way to do this?
I investigated doing something like this once, and this tutorial http://yergler.net/blog/2009/09/27/nested-formsets-with-django/ was fairly helpful.
Another way to do this is:
def my_view(request):
MyFormSet = formset_factory(MyForm, extra=2, can_order=True)
if request.method == 'POST':
form = MainForm(request.POST)
formset = MyFormSet(request.POST, other_form = form)
if form.is_valid() and formset.is_valid(): # <-- ?!?!
# The formset is now validated based on the form
Then
class MyFormSet(...):
def __init__(self, *args, **kwargs):
if kwargs.has_key('other_form'):
self.myformforlater = kwargs.pop('other_form')
Super(MyFormSet, self).__init__(*args, **kwargs)
This way you only have to override the init method, and you have access to the outer form from any validation step.
Here's the code I ended up with, using Ted's answer (django 1.3):
class BaseMyFormSet(BaseFormSet):
main_form = None
def __init__(self, *args, **kwargs):
# Save the main form until validation
if kwargs.has_key('main_form'):
self.main_form = kwargs.pop('main_form')
super(BaseMyFormSet, self).__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
# Don't bother validating the formset unless each
# form is valid on its own
return
checkbox = self.main_form.cleaned_data['my_checkbox']
if checkbox:
for form in self.forms:
# Do some extra validation
def my_view(request):
MyFormSet = formset_factory(MyForm, extra=2, can_order=True,
formset=BaseMyFormSet)
if request.method == 'POST':
form = MainForm(request.POST)
formset = MyFormSet(request.POST, main_form=form)
if form.is_valid() and formset.is_valid():
# The formset is now validated based on the form

Django dynamic form ValidationErorr

I'm trying to modify the admin ModelMultipleChoiceField so it does load data dynamically.
Because I want to load data dynamically the queryset for ModelMultipleChoiceField is empty when creating an instance of the form, for that reason when doing form validation django complains that the choices aren't valid because they can't be found in the queryset.
Is there any way around this ?
FORM:
class FormName(forms.ModelForm):
dinamic_field = forms.ModelMultipleChoiceField(Entry.objects.none(),widget=
widgets.FilteredSelectMultiple("", False))
class Meta:
model = ModelName
fields = ('dinamic_field',)
class Media:
js = ('jquery.js', 'dinamic_field.js')
VIEW:
def add(request):
if request.method == 'POST':
form = FormName(request.POST)
if request.is_ajax():
obj = Packages.objects.get(id = form.data['package'])
form.fields['dinamic_field'].queryset = Entry.objects.filter(test__in =obj.all())
return HttpResponse(form['dinamic_field'])
if form.is_valid():
job = form.save()
return HttpResponseRedirect('../../')
else:
form = FormName()
return return render_to_response('/template_name', {'form': 'form'})
Have you tried overriding your form's __init__() method and setting the queryset for the field? Something like:
class JobForm(forms.ModelForm):
dynamic_field = forms.ModelMultipleChoiceField(Entry.objects.none(),widget=
widgets.FilteredSelectMultiple("", False))
def __init__(self, *args, **kwargs):
super(JobForm, self).__init__(*args, **kwargs)
self.dynamic_field.queryset = Entry.objects.<etc>