how can I prevent users form extending/ minimizing TextField Django - django

How can I prevent this from happening

A Django TextField is rendered as a HTML textarea.
Looking at this question, you could use style="resize: none;".
If you would like to add that in your views/form (and not in the templates), you could try something like:
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['my_field_name'].widget.attrs['style'] = 'resize: none;'
or if you have a form instance
form.fields['my_field_name'].widget.attrs['style'] = 'resize: none;'

Related

Why does adding more fields to this widget lead to a keyError?

I'm working on a form in my Django project. I wanted to add a bootstrap class to my input fields.
I tried to do this with the following code:
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = '__all__'
labels = {
"sub_category":"Sub category (if any):"
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category_name','sub_category','category_info','category_video'].widget.attrs.update({'class':'form-control'})
But when I load the page I get this:
KeyError at /academy/category_form
('category_name', 'sub_category', 'category_info', 'category_video')
Is this not possible? Do I have to add a new line for every field in my form? So like this:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category_name'].widget.attrs.update({'class':'form-control'})
self.fields['sub_category'].widget.attrs.update({'class':'form-control'})
self.fields['category_info'].widget.attrs.update({'class':'form-control'})
....
This would make for some long lines of code if I have to do this for every form which does not make sense of follow DRY.
Within the form fields is a dictionary containing the form fields. It is not doing what you expect it to do ...your list of keys is interpreted as a tuple and that tuple is not in the form fields contained, that results in the mentioned KeyError.
Now to your attempt to not repeat yourself ... you can use a loop to avoid this:
for key in ('category_name', 'sub_category', 'category_info', 'category_video'):
self.fields[key].widget.attrs.update({'class':'form-control'})

Prepopulate non-model form attribute when instantiating in Django

I want to set a minimum value for a DecimalField attribute on a form at the time when I instantiate it in the view. And I want to get that minimum value from an object I gather from the database. I made it (sort of) work by manually putting in the html form in the template, but want to refactor it to use the form class because I can do more useful things with data in the view than I can in the template.
Based on my reading of other questions and docs, I can't set attributes with the .initial argument. I thought likely I need to override the __init__ method on the form, but I'm pretty sure I'm not doing this right and it makes no sense syntactically. Here's what I have tried:
class BidForm(forms.Form):
bid = forms.DecimalField(decimal_places=2)
listing_bid = forms.CharField(widget=forms.HiddenInput())
def __init__(self, min_bid, listing_pk, *args, **kwargs):
super(BidForm, self).__init__(*args, **kwargs)
self.fields['bid'].min = min_bid
self.fields['listing_bid'] = listing_pk
My idea is to have this form take a min_bid and a listing_pk, and fill the "min" attribute on the html input with whatever is in the min_bid variable. I want to put the listing_pk that's passed in as the value in a hidden field called "listing_bid". If it helps clarify, I'm trying to generate html equivalent to:
<input type="number" name="bid" min="{{ listing.current_bid }}">
<input type="hidden" name="listing_bid" value="{{ listing.pk }}">
In the view, I'd like to say something like:
form = BidForm(min_bid=foo, listing_bid=bar)
Then pass that into the template context for rendering.
Does this make sense? I've found some discussion of it in the context of ModelForms but can't wrap my head around how to do this with regular forms.
Edit: for future reference, here is what worked for me. I deleted the bid attribute on the form because there's no case where I would want to init it without supplying a min_bid:
class BidForm(forms.Form):
listing_bid = forms.CharField(widget=forms.HiddenInput())
def __init__(self, min_bid, listing_pk, *args, **kwargs):
super(BidForm, self).__init__(*args, **kwargs)
self.fields['bid'] = forms.DecimalField(decimal_places=2, min_value=min_bid)
self.fields['listing_bid'].initial = listing_pk
You can make use of .initial attribute:
class BidForm(forms.Form):
bid = forms.DecimalField(decimal_places=2)
listing_bid = forms.CharField(widget=forms.HiddenInput())
def __init__(self, min_bid, listing_pk, *args, **kwargs):
super(BidForm, self).__init__(*args, **kwargs)
self.fields['bid'].min_value = min_bid
self.fields['listing_bid'].intial = listing_pk

Django get field rendering as string

How can I get a field rendering from html after form init?
I am trying to add some custom html to the form like this:
class BaseForm(Form):
render_report = forms.BooleanField(required=False, initial=False)
def __init__(self, *args, **kwargs):
super(BaseForm, self).__init__(*args, **kwargs)
html_rendering = str(self.fields['render_report'])
The conflicting part is str(self.fields['render_report']). How can I obtain the html rendering of render_report?. Of course, str() doesn't work.
After some headbanging, here is the catch:
The rendered fields are accesed via the form's _ _ getitem _ _().
So I had to change self.fields['render_report'] for self['render_report']

Crispy Forms Initial data

I'm confused on whether I can set initial data to a field with crispy forms. I have one field in which I generate a number and want to set that to a specific field. If I do anything like:
def __init__(self, *args, **kwargs):
self.fields['medical_record_number'].initial = 'whatever you want'
I get a error stating that name 'self' is not defined.
I am assuming there is something different I have to do while using crispy forms to accomplish the same thing?
Thanks,
Tom
Nothing to do with crispy-forms, this is regular Django forms code. You have forgotten to call parent constructor, if you are using python 2.X do:
def __init__(self, *args, **kwargs):
super(YourFormClassName, self).__init__(*args, **kwargs)
self.fields['medical_record_number'].initial = 'whatever you want'
Beware that maybe you prefer to set initial in your Django form field:
whatever = forms.CharField(initial="whatever you want")

adding new form fields dynamically in admin

I am trying to add dynamically new form fields (I used this blog post), for a form used in admin interface :
class ServiceRoleAssignmentForm(forms.ModelForm):
class Meta:
model = ServiceRoleAssignment
def __init__(self, *args, **kwargs):
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)
self.fields['test'] = forms.CharField(label='test')
class ServiceRoleAssignmentAdmin(admin.ModelAdmin):
form = ServiceRoleAssignmentForm
admin.site.register(ServiceRoleAssignment, ServiceRoleAssignmentAdmin)
However, no matter what I try, the field doesn't appear on my admin form ! Could it be a problem related to the way admin works ? Or to ModelForm ?
Thank for any help !
Sébastien
PS : I am using django 1.3
When rendering your form in template, fields enumerating from fieldsets variable, not from fields. Sure you can redefine fieldsets in your AdminForm, but then validations will fail as original form class doesn't have such field. One workaround I can propose is to define this field in form definition statically and then redefine that field in form's init method dynamically. Here is an example:
class ServiceRoleAssignmentForm(forms.ModelForm):
test = forms.Field()
class Meta:
model = ServiceRoleAssignment
def __init__(self, *args, **kwargs):
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)
# Here we will redefine our test field.
self.fields['test'] = forms.CharField(label='test2')
I actually have a the same issue which I'm working through at the moment.
While not ideal, I have found a temporary workaround that works for my use case. It might be of use to you?
In my case I have a static name for the field, so I just declared it in my ModelForm. as normal, I then override the init() as normal to override some options.
ie:
def statemachine_form(for_model=None):
"""
Factory function to create a special case form
"""
class _StateMachineBaseModelForm(forms.ModelForm):
_sm_action = forms.ChoiceField(choices=[], label="Take Action")
class Meta:
model = for_model
def __init__(self, *args, **kwargs):
super(_StateMachineBaseModelForm, self).__init__(*args, **kwargs)
actions = (('', '-----------'),)
for action in self.instance.sm_state_actions():
actions += ((action, action),)
self.fields['_sm_action'] = forms.ChoiceField(choices=actions,
label="Take Action")
if for_model: return _StateMachineBaseModelForm
class ContentItemAdmin(admin.ModelAdmin):
form = statemachine_form(for_model=ContentItem)
Now as I mentioned before, this is not entirely 'dynamic', but this will do for me for the time being.
I have the exact same problem that, if I add the field dynamically, without declaring it first, then it doesn't actually exist. I think this does in fact have something to do with the way that ModelForm creates the fields.
I'm hoping someone else can give us some more info.
Django - Overriding get_form to customize admin forms based on request
Try to add the field before calling the super.init:
def __init__(self, *args, **kwargs):
self.fields['test'] = forms.CharField(label='test')
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)