read only attribute is safe in django forms? - django

Setting read only attrs for django forms is safe?. In my django projects I do something like this:
def someUpdateView(request):
form = EmployeeForm(instance=Employeem.objects.get(pk=1))
return render...
class EmployeeForm(forms.ModelForm)
declaring here read only attrs field by widgets dict in Meta class or in init method (i.e. pk fields or other fields like email for keeping inmutable).
But what if an user opens web browser inspector mode and edits html field value or deletes read only attribute? during form.save() django will save the new value even it was read only (from html) and if this happens, there is a way to handle that?.

Related

FormView - Specify which fields are sent in the POST

Given a FormView associated to a Form, once the form is submitted some fields are sent to the FormView (those the user has filled).
Question: How can I send to the FormView other fields even if the user didn't fill them (because the fields were already prepopulated)? I need more data than the user provides in order to be used in form_valid
If the data is not sensitive you might want to add them to your form as hidden fields. In django you can achieve this with a FormWidget. There are a few related questions here on SO:
Change a django form field to a hidden field
Django ModelForm to have a hidden input
Be aware that this just hides your data in the user interface, not in the browser - if you are in trouble if someone will change this data in an evil matter, you might consider writing the data in the session.

How to map HTML form data to Django model

I have a (quite complex) HTML form full of logic that triggers based on different choices in the selectpickers with fields that don't have quite the same names as the corresponding fields in the Django model, and sometimes I fear that I will need to add some logic when it comes to going from the data sent from the HTML form and to the Django model. I realise that I can probably not use a ModelForm in Django to handle this and have been looking for some examples of using the standard django.forms.Form to map the HTML form into my model but I haven't really found much. Can someone give me some hints?
It sounds as though your html form already exists and somehow you want to read in the POST data from that form. Without making any further assumptions as to how you ended up with an html form without a django ModelForm or forms.Form output via a view - as long as the form action location is mapped via a route to a view - the view can then process the request.POST data. Again all form validation goodness of django is out the door if you did not use django forms (model or forms based) and you have to do your own validations in the view then. Once the form data has been validated, initialize your model object like this: my_obj = ModelName(field_name1=form_input_data1, field_name2=form_input_data2, ...) and that's it. Then you can do my_obj.save().
Now let's say, it's not so bad. You actually are using the forms.Form inheritance to create your django-istic form class which has no direct relationship with the model. Now you can use the form related validation clean_field and clean steps etc... as well as all the built-in field types internal validation django automatically does. Then when you read in the POST data - do whatever it takes to map the form fields (via any transformation as necessary) to the django model object you are trying to construct, keeping in mind the default values and any model save custom assignments that may happen.
You can not just map a html form into your django model. You need to create a model form first and then render it in html.
If you want to somehow map your html form to model. First render your ModelForm in html. Create the exact copy of the html format of your django form and use it in html. Catch that in your view and process it like model form. But anyway you have to create the ModelForm.

Specifying specific form format in Django

I am using materializecss to give my django site some material elements. I have put together a form (the 'old' way using html) but now realised I need to use a django form instead. The problem is, these forms don't play well with materialises built in column system (they use classes to determine rows and column spacing). Here is an example of the layout I set up so far. However when defining the form through form.py, it spits out one input per layer.
My question is: what can I do to either a) get django to work with the html-defined form or b) make a 'form template' to give the input fields the appropriate classes?
If you want to see the code I can post some but I'm quite a new coder so it's messy.
Thanks!
There are three ways I can think of off the top of my head.
If you want full control over the HTML form, in a Django template or HTML form, simply map the names of your fields to match the underlying field names in the Django form. This way, when POSTed back to your view, Django will automatically link up the POSTed fields with the Django form fields.
For example, if you have a field username in your Django form (or Django model if using ModelForm), you could have an element <input type="text" name="username" maxlength="40"> (that you can style any way you need) on your HTML form that Django will happily parse into your Django form field, assuming your view is plumbed correctly. There is an example of this method in the Django documentation.
Another way is to customize the Django form field widgets in your Django form definition. The Django documentation talks a little bit about how to do this. This is great for one offs, but is probably not the best approach if you expect to reuse widgets.
The final approach would be to subclass Django form field widgets to automatically provide whatever attributes you need. For example, we use Bootstrap and have subclassed nearly all of the widgets we use to take advantage of Bootstrap classes.
class BootstrapTextInput(forms.TextInput):
def __init__(self, attrs=None):
final_attrs = {'class': 'form-control'}
if attrs is not None:
final_attrs.update(attrs)
super().__init__(attrs=final_attrs)
Then it's simply a matter of letting the Django form know which widget to use for your form field.
class UsernameForm(forms.ModelForm):
class Meta:
model = auth.get_user_model()
fields = ['username']
widgets = {'username': BootstrapTextInput()}
Hope this helps. Cheers!

avoid loading all choices in ModelChoiceField for loading values throug ajax

I am trying to create a form with ModelChoice field. The field is filtered by ajax request.
self.fields['center'].queryset = TrainingCenter.objects.all()
this is works fine. but I am loading the values using ajax based on another field.
if I use a empty queryset to load the form without choices, I am getting "Invalid Choice" error on submit.
how to avoid loading all the choices without making error on submission
You can write an EmptySelect widget class that ignores the choices that are passed to it, like this:
from django import forms
class EmptySelect(forms.Select):
def _get_choices(self):
return ()
def _set_choices(self, value):
pass
choices = property(_get_choices, _set_choices)
Then, define your field with the queryset that you want to validate against and configure EmptySelect as your widget.
center = forms.ModelChoiceField(
queryset=TrainingCenter.objects.all(),
widget=EmptySelect
)
You can inherit from other choice widgets too, or even turn EmptySelect into a mixin that you can use with any choice widget.

Insert django form into template dynamically using javascript?

I want to add same django form instance on same template. i already add one before and other add dynamically using javascript.
for example 'form" is a django form: newcell.innerHTML = {{ form.firstname }};
The problem is that when i submit the form, in view the request object has only one value (that is not add using javascript). how can i get the values of other form elements values that is added dynamically runtime.
It is something like the "Attach Another File" feature in gmail, where the user is presented with a file upload field and new fields are added to the DOM on the fly as the user clicks to "Attach Another File" plus button
You could always try separating out your FileField into a FileModel.
Take a look at the following pseudo code (as in python based on memory--i've moved over to clojure for now).
models.py
class FileModel(models.Model):
file = models.FileField()
...
class ThingToWhichYoureAttaching(models.Model):
name = models.CharField()
attachments = models.ManyToManyField(FileModel)
...
forms.py
class FileForm(forms.ModelForm):
class Meta:
model=FileModel
class ThingForm(forms.ModelForm):
attachments = forms.MultipleChoiceField()#override the manytomany form field with style field of your choice.
class Meta:
model=ThingToWhichYoureAttaching
When they pop up the window with the PLUS button, show the FileForm but on the main page leave the ThingForm untouched. You can also have an initial FileField on the main page with the ThingForm for people who don't have javascript. Just make sure to process the FileForm BEFORE the ThingForm so that the File is available for the Thing.
When processing the popup form you can use AJAX (i recommend jquery) to submit the FileForm to the server, and return the markup to insert the File in the Attachments field.