I am trying to display a form with Django, but I want to remove a field if the user language is 'en'. I would like to avoid doing it in Javascript or doing a second template just for it. So I wonder if it possible to pass parameter to the Meta() class of my UserForm() class. That way I could pass the user and check with an if statement his language.
Here is what I have so far:
class UserForm(forms.ModelForm):
first_name = forms.CharField(required=True, label=_('*First name'))
last_name = forms.CharField(required=True, label=_('*Last name'))
postal_code = FRZipCodeField(required=False, label=_('My postcode'))
birthday = forms.DateField(
widget=forms.DateInput(format='%d/%m/%Y'),
required=False,
input_formats=['%d/%m/%Y'],
label=_('My birthday'))
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('gender'),
Field('first_name'),
Field('last_name'),
Field('birthday'),
Field('country'),
Field('language'),
Field('payment_preference'),
Div('addr1', css_class='hidden', css_id='addr1_container'),
Div('addr2', css_class='hidden', css_id='addr2_container'),
Div('addr3', css_class='hidden', css_id='addr3_container'),
Div('postal_code', css_class='hidden', css_id='pc_container'),
Div('city', css_class='hidden', css_id='city_container'),
ButtonHolder(
Submit('save', _('update'), css_class='pull-right'),
)
)
class Meta():
model = User
fields = (
"first_name", "last_name", "gender", "birthday", "country",
"payment_preference", "addr1", "addr2", "addr3", "postal_code",
"city", "language",)
With an if, I could set two different fields variable in the Meta() class and so show two different forms for each user language.
You can't pass it into the Meta, but you can pass it into the __init__ and hide the field you want to hide:
class UserForm(forms.ModelForm):
# ... as before
def __init__(self, user, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
if user.language == 'en':
self.fields['field_name'].widget = forms.HiddenInput()
# ... as before
Then when you call the form, pass the user as the first argument:
form = UserForm(request.user, ...)
Related
I have a CreateView where I want to create a new price for a product. The product detail page has a button to change the price which leads to a new page like ...\partprice\X where X is the id of the product. A product can have multiple prices, which is the reason why I am using a CreateView. Is the only way to grab the part_id from the URL (like here)?
In the forms.py:
class PPriceFormset(ModelForm):
required_css_class = "required"
class Meta:
model = PPrice
fields = ("price", "customer", "date", "part")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'POST'
self.helper.layout = Layout(Row(Column('price'),
Column('customer')),
Submit('submit', 'Save price', css_class='btn-primary'),
Field("date", type="hidden"),
Field("part", type="hidden"))
I want to add the X from above into the hidden field "part". In the view I already have it:
class PPrice(CreateView):
model = PPrice
template_name ="gap/pprice_update.html"
form_class = PPriceFormset
success_url = reverse_lazy('part-list')
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(PPriceCreateView, self).get_form_kwargs(*args, **kwargs)
kwargs['part_id'] = self.kwargs.get("part_pk")
return kwargs
The solution was quite easy, the class needed an initial value that could be passed on to the form via get_initial.
class PPriceCreateView(CreateView):
model = PPrice
template_name ="gap/pprice_update.html"
form_class = PPriceFormset
success_url = reverse_lazy('part-list')
def get_initial(self):
return {"part": self.kwargs["part_pk"]}
I have a manytomany object in a model form which I want to be rendered as select fields under each other, but whatever I try, i keep getting them next to each other with crispy django forms
class ContactForm(forms.ModelForm):
choice = forms.ModelMultipleChoiceField(label=_('Request'), widget=forms.CheckboxSelectMultiple(),required=False,
queryset=ContactFormChoices.objects.all())
name = forms.CharField(label=_('Name'))
email = forms.EmailField(required=False, label=_('E-mail'))
phone_number = forms.CharField(required=False, label=_('Phone number'))
message = forms.CharField( widget=forms.Textarea , label=_('Message'))
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.layout = Layout(
Field('name', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
Field('phone_number', css_class='input-xlarge'),
Field('message', rows="3", css_class='input-xlarge'),
#'choice',
Field('choice'),
FormActions(
Submit('submit', _('Submit'), css_class="btn-primary")
)
)
class Meta:
model = ContactData
fields = ['name','message','email','phone_number','choice']
and the model:
class ContactFormChoices(models.Model):
'''
The contact form options to show
'''
text = models.CharField(max_length=256)
active = models.BooleanField(default=True)
def __unicode__(self):
return self.text
class ContactData(models.Model):
'''
The contact data (when customer fills in the contact form,
this is mailed and saved here
'''
name = models.CharField(max_length=256,help_text=_("Name"))
phone_number= models.CharField(max_length=256,null=True,blank=True,default=None)
email = models.EmailField(max_length=256,null=True,blank=True,default=None)
choice = models.ManyToManyField(ContactFormChoices,blank=True,default=None)
message = models.TextField()
def __unicode__(self):
return self.name
it looks like this:
Anybody any suggestion?
wow, after searching and trying a lot.... the answer seem to be very simple:
helper.layout = Layout(
Field('name', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
Field('phone_number', css_class='input-xlarge'),
Field('message', rows="3", css_class='input-xlarge'),
PrependedText('choice', ''),
FormActions(
Submit('submit', _('Submit'), css_class="btn-primary")
)
)
and partly duplicate to this question and answer: BooleanField checkbox not render correctly with crispy_forms using bootstrap
I have this model in models.py:
class Life_events(models.Model):
patient = models.ForeignKey(Demographic)
HSCT_date = models.DateField('HSCT date',null=True,blank=True)
HSCT_outcome = models.CharField('HSCT outcome',max_length=100, null=True, blank=True)
partaker_in_clinical_trial= models.CharField('Partaker in clinical trial',max_length=200, null=True, blank=True)
date_of_input= models.DateField(null=True,blank=True)
def __str__(self):
return str(self.patient)
My forms.py contains:
class LifeEventsForm(forms.Form):
def __init__(self, *args, **kwargs):
super(LifeEventsForm, self).__init__(*args, **kwargs)
self.helper=FormHelper(self)
self.helper.field_class = 'col-md-8'
self.helper.label_class = 'col-md-3'
self.helper.layout = Layout(
Fieldset (
'<b>HSCT</b>',
Div(
#HTML(u'<div class="col-md-2"></div>'),
Div('HSCT_date',css_class='col-md-6'),
Div('HSCT_outcome',css_class="col-md-6"),
Div('partaker_in_clinical_trial', css_class='col-md-6'),
css_class='row',
),
),
FormActions(
Submit('submit', "Save changes"),
Submit('cancel',"Cancel")
),
)
self.helper.form_tag = False
self.helper.form_show_labels = True
class Meta:
model = Life_events
exclude = ['patient', 'date_of_input']
My views.py has:
my_life_ev = LifeEventsForm(prefix='life_ev')
return render_to_response('input.html', {'frm_life_ev': my_life_ev,}, context)
And my template file input.html has:
{%crispy frm_life_ev%}
When I render my template I can't see the form fields but only the word 'HSCT' which I have in Fieldset. My html code does not contain the fields at all.
Any ideas please?
Your form inherits from forms.Form, which does not know anything about models and ignores the Meta class. You should inherit from forms.ModelForm.
You need to declare a ModelForm. A simple Form won't do.
class LifeEventsForm(forms.ModelForm)
How to set first default rows/values in django admin's inline?
class Employee(models.Model):
username = models.CharField(_('Username'), max_length=150, null=False, blank=False)
email = models.CharField(_('Email'), max_length=150, null=False, blank=False)
class Details(models.Model):
employee = models.ForeignKey(Employee, verbose_name=_('Employee'), blank=False, null=False)
label = models.CharField(_('Label'), max_length=150, null=False, blank=False)
value = models.CharField(_('Value'), max_length=150, null=False, blank=False)
class DetailsFormset(forms.models.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
self.initial = [
{ 'label': 'first name'},
{'label': 'last name'},
{'label': 'job',}]
super(DetailsFormset, self).__init__(*args, **kwargs)
class DetailsInline(admin.TabularInline):
model = Details
formset = DetailsFormset
fieldsets = [
['', {'fields': ['employee', 'label', 'value']}]
]
class EmployeeAdmin(admin.ModelAdmin):
inlines = [DetailsInline]
but this row doesn't work
self.initial = [
{ 'label': 'first name'},
{'label': 'last name'},
{'label': 'job',}]
How do I set default values using django admin?
from django.utils.functional import curry
class DetailsInline(admin.TabularInline):
model = Details
formset = DetailsFormset
extra = 3
def get_formset(self, request, obj=None, **kwargs):
initial = []
if request.method == "GET":
initial.append({
'label': 'first name',
})
formset = super(DetailsInline, self).get_formset(request, obj, **kwargs)
formset.__init__ = curry(formset.__init__, initial=initial)
return formset
From here: Pre-populate an inline FormSet?
If what you need is to define default values for the new forms that are created you can redefine the empty_form property of a InlineFormSet:
class MyDefaultFormSet(django.forms.models.BaseInlineFormSet):
#property
def empty_form(self):
form = super(MyDefaultFormSet, self).empty_form
# you can access self.instance to get the model parent object
form.fields['label'].initial = 'first name'
# ...
return form
class DetailsInline(admin.TabularInline):
formset = MyDefaultFormSet
Now, every time you add a new form it contains the initial data you provided it with. I've tested this on django 1.5.
I tried many suggestions from Stackoverflow (Django=4.x), not working for me.
Here is what I did.
class MilestoneFormSet(forms.models.BaseInlineFormSet):
model = Milestone
def __init__(self, *args, **kwargs):
super(MilestoneFormSet, self).__init__(*args, **kwargs)
if not self.instance.pk:
self.initial = [
{'stage': '1.Plan', 'description': 'Requirements gathering', },
{'stage': '2.Define', 'description': 'Validate requirement', },
]
class MilestoneInline(admin.TabularInline):
model = Milestone
formset = MilestoneFormSet
def get_extra(self, request, obj=None, **kwargs):
extra = 0 #default 0
if not obj: #new create only
extra = 2 #2 records defined in __init__
return extra
I hope this works for everyone.
To provide a static default for all instances in the inline, I found a simpler solution that just sets it in a form:
class DetailsForm(django_forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['label'] = 'first_name'
class DetailsInline(admin.TabularInline):
form = DetailsForm
# ...
I think this doesn't work for the OP's particular case because each form has a different value for the 'label' field, but I hope it can be useful for anyone coming to this page in the future.
I want to be able to add fields to django admin form at runtime. My model and form:
#admin.py
class SitesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SitesForm, self).__init__(*args, **kwargs)
self.fields['mynewfield'] = forms.CharField()
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites,SitesAdmin)
#model.py
class Sites(models.Model):
url = models.URLField(u'URL')
is_active = models.BooleanField(default=True, blank=True)
is_new = models.BooleanField(default=False, blank=True)
group = models.ForeignKey('SitesGroup')
config = models.TextField(blank=True)
Field mynewfield isn't displayed in form. Why?
You shouldn't be adding a new field to your form in that way, you can just do it as you would any other field and the form will contain both the Model's original fields and your new fields:
class SitesForm(forms.ModelForm):
mynewfield = forms.CharField(max_length=255, blank=True)
class Meta:
model = Sites
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites, SitesAdmin)
Edit: Sorry, should have read what you had written a little better. If you want a dynamic field like that, then you need to do the following and it will do exactly what you want:
class SitesForm(forms.ModelForm):
class Meta:
model = Sites
def __init__(self, *args, **kwargs):
self.base_fields['mynewfield'] = forms.CharField(max_length=255, blank=True)
super(SitesForm, self).__init__(*args, **kwargs)
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites, SitesAdmin)
It's the base_fields that gets composed by the metaclass that holds the fields that the form will use.
Solution:
class AdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AdminForm, self).__init__(*args, **kwargs)
self.fields.insert(1, 'myfield', forms.CharField())
class MyAdmin(admin.ModelAdmin):
form = AdminForm
def get_fieldsets(self, request, obj=None):
return (
(None, {
'fields': (..., 'myfield',),
}),
)