Django different forms for admin model - django

Is there any way to load different admin forms for editing an objects depending of what object is needed to be updated?
For example - we have an MPTTModelAdmin objects. And for root objects we don't want to see some fields:
class RootObjectForm(ModelForm):
class Meta:
model = Author
exclude = ('title',)
class ChildObjectForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'birth_date')
But I don't know how to get object fields in forms.py or admin.py.

You can always supply your own form class for a ModelAdmin class: https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
From there you can access fields by key, just like any other Django form:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
super(MyModeForm, self).__init__(*args, **kwargs)
# access whatever field by key
# self.fields['field-name']

In forms.py file you can get object fields and their value at two stages.
1 : when form is submitted.
clean method does initial validations.
def clean(self):
""" validation of address form """
cleaned_data = super(WebsiteAddressForm, self).clean()
field1_value = self.cleaned_data.get("field1")
print field1_value
return cleaned_data
2 : when form is initialized. ____init____ method will call.
class MyForm(forms.ModelForm):
class Meta:
model = Model1
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
#self.fields['field1']

Related

How can i change queryset on SelectField?

I have a form, and a select input, i need change the queryset of tthat select, how can i make this?
my form exemple:
class myModelForm(forms.ModelForm):
class Meta:
model = myModel
fields = '__all__'
Try overriding __init__ and setting the queryset on your field:
class myModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['<your_field_name'].queryset = <your_queryset>
if you want to make a form to catch only some of the field of the model you have to specify such field:
class Meta:
model = myModel
fields = ['field1','field3','field12']
if you mean that you want to make a change into the form after you get it into your view:
form = myModelForm(request.POST)
form.cleaned_data['field1'] = 'change what you want'

Python Django ModelForm, how can I modify a form fields before rendering it depending on the model

Using a ModelForm, the model contains a value of a field I should render in the form :
class MyClass(models.Model):
my_field = models.CharField(max_length=256) # this contains the type of the form's field for example a CharField or a DateTimeField
My view :
class MyView(FormView):
form_class = CustomForm
model = MyClass
And the form class:
class MyForm(forms.ModelForm):
class Meta:
model = MyClass
fields = ?
How can I dynamically set my form's field type?
I'd list out all the possible fields you may need in fields = () then you can remove fields you don't want, change if fields are required etc, based on the value of the model field like this;
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
if self.instance:
if self.instance.my_field == 'value':
del self.fields['my_field'] # remove 'my_field'
self.fields['name'].required = False # change required value
class Meta:
model = MyClass
fields = (
'name',
'address',
'my_field',
'some_other_field'
)
So from your view, if you want to get a value to your form you can do something like;
my_object = MyClass.objects.first()
form = MyForm(instance=my_object)
context['form'] = form
# etc, etc
Then you can get values from fields on that object like I suggested above.
You could also just pass arbitrary args/kwargs to your forms if you need to (say you don't actually have an object to check the values from, but instead want to just pass something based on other data;
# in a view;
form = MyForm(my_var='something')
# in the form;
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
my_var = kwargs.pop('my_var')
super(MyForm, self).__init__(*args, **kwargs)
if my_var == 'value':
del self.fields['my_field'] # remove 'my_field'

Django manytomany field is absent in modelform

Suppose I have following Model
class Member(models.Model):
name = ...
qualities = models.ManyToManyField(ProfessionalQuality, related_name='members')
And following form:
class CommonMemberForm(forms.ModelForm):
"""This form for gathering common features in both admin and member forms
"""
class Meta:
model = Member
fields = '__all__'
def __init__(self, *args, **kwargs):
super(CommonMemberForm, self).__init__(*args, **kwargs)
self.fields['qualities'].validators.append(...)
When I try to instantiate form, I get KeyError: 'qualities' are not in self.fields. Why is that?
This code works in admin.
What is the correct way of handling such fields?
Try this:
class CommonMemberForm(forms.ModelForm):
"""This form for gathering common features in both admin and member forms
"""
class Meta:
model = Member
fields = '__all__'
widgets = {
'qualities': forms.CheckboxSelectMultiple()
}
def __init__(self, *args, **kwargs):
super(CommonMemberForm, self).__init__(*args, **kwargs)
#self.fields['qualities'].widget...
This works for me:
class CommonMemberForm(AbstractUser):
class Meta:
model = Member
fields = '__all__'
def __init__(self, *args, **kwargs):
super(RegularUser, self).__init__(*args, **kwargs)
self._meta.get_field('qualities').validators = [validate_qualities]

Django model form - Exclude a field that has no model field

I have a simple model form what I use through the admin interface. Some of my model fields store datas that require a bit more time to calculate (they come from other sites). So I decided to put an extra boolean field to the form to decide to crawl these datas again or not.
class MyModelForm(forms.ModelForm):
update_values = forms.BooleanField(required=False) #this field has no model field
class Meta:
model = MyModel
This extra field doesn't exist in the model because only the form needs it.
The problem is that I only want it to appear if it's an existing record in the database.
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance.pk is None:
#remove that field somehow
I tried nearly everything. Exclude it, delete the variable but nothing wants to work. I also tried dynamically add the field if self.instance.pk is exists but that didn't work too.
Any idea how to do the trick?
Thanks for your answers.
You could subclass the form and add the extra field in the subclass:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
class MyUpdateModelForm(MyModelForm):
update_values = forms.BooleanField(required=False) #this field has no model field
class Meta:
model = MyModel
You can then override the get_form method of your admin, which is passed the current instance: get_form(self, request, obj=None, **kwargs)
Rather than removing the field in __init__ if instance.pk is not None, how about adding it if it is None? Remove the class-level declaration and just change the logic:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk is not None:
self.fields['update_values'] = forms.BooleanField(required=False)

CBV Django Form View set data for ChoiceField

I'm using the Django Form View and I want to enter custom choices per user to my Choicefield.
How can I do this?
Can I use maybe the get_initial function?
Can I overwrite the field?
When I want to change certain things about a form such as the label text, adding required fields or filtering a list of choices etc. I follow a pattern where I use a ModelForm and add a few utility methods to it which contain my overriding code (this helps keep __init__ tidy). These methods are then called from __init__ to override the defaults.
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('country', 'contact_phone', )
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
self.set_querysets()
self.set_labels()
self.set_required_values()
self.set_initial_values()
def set_querysets(self):
"""Filter ChoiceFields here."""
# only show active countries in the ‘country’ choices list
self.fields["country"].queryset = Country.objects.filter(active=True)
def set_labels(self):
"""Override field labels here."""
pass
def set_required_values(self):
"""Make specific fields mandatory here."""
pass
def set_initial_values(self):
"""Set initial field values here."""
pass
If the ChoiceField is the only thing you're going to be customising, this is all you need:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('country', 'contact_phone', )
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
# only show active countries in the ‘country’ choices list
self.fields["country"].queryset = Country.objects.filter(active=True)
You can then make your FormView use this form with like this:
class ProfileFormView(FormView):
template_name = "profile.html"
form_class = ProfileForm