Just to be clear, I'm asking about accessing the fields in views.py
I want to add extra data into the form before it is validated (because it's a required field), and another answer on stackexchange seems to imply I have to create a new form to do so.
Right now my code look something like this:
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = TestForm(request.POST)
data = {}
for ---:
---add to data---
comp = Component.objects.get(name = path)
data['component'] = comp.id
form = TestForm(data)
if form.is_valid():
test = form.save(commit = 'false')
test.save()
return submitTest(request, var)
How could I fill in the parts with dashes?
This is the wrong thing to do. There is no reason to add in a required field programmatically; if you know the value of the field already, there is no reason to include it on the form at all.
I don't know what you mean about having to create another form; instead you should explicitly exclude that field, in the form's Meta class, and set the value on the test object before calling test.save().
Edit after comment I still don't really understand why you have data coming from two separate places, but maybe you should combine them before passing to the form:
data = request.POST.copy()
data['myvalue'] = 'myvalue'
form = MyForm(data)
I figured out what I was doing wrong. In my TestForm modelform I didn't include the 'component' field because I didn't want it to show up on the form. As a result, the 'component' data was being cleaned out during form validation even if I inserted it into the form correctly. So to solve this I just added 'component' into the fields to display, and to hide it on the form I added this line
widgets = {'component': HiddenInput()}
to the TestForm class in forms.py.
Related
Let's say I have a Django form with ChoiceField:
class MyForm(forms.Form):
name = forms.CharField(label="Name", required=True)
some_object = forms.ChoiceField(label="Object", choices=[(0, '-----')] + [(x.id, x.name) for x in Obj.objects.all()])
Choisefield is being initialized with list of objects headed by 'empty choice'. There is no object with pk=0.
In that form I have a clean() method:
def clean(self):
if not Obj.objects.filter(self.cleaned.data['some_object'].exists():
self.errors.update({'some_object': ['Invalid choice']})
It works well when I'm sending a form to a server, if data in it doesn't match conditions, field.is_valid returns False and I render form with error messages. But, when I create an empty form like this:
if request.method == 'GET':
data = {'name': 'Untitled',
'some_object': 0}
form = MyForm(data)
return render(request, 'app\template.html', {'form': form})
Django renders form with error message ('Invalid choice') even though form was just created and 'Object' select was intended to be set in empty position. Is it possible to disable form clean() method in specific cases? Or maybe I'm doing this all wrong? What is the best practice to create an empty form?
The problem is that a form with any data dictionary passed to it counts as a "bound" form, against which Django will perform data validation. See here for details: https://docs.djangoproject.com/en/2.1/ref/forms/api/#bound-and-unbound-forms
You want an "unbound" form - to have default initial values in here, just set the initial property on your form fields. See full details here: https://docs.djangoproject.com/en/2.1/ref/forms/fields/#initial
I'm having big trouble understanding the whole forms business in django. As I understand it the cleaned form data is a dictionary. So all my defined form fields should be in the dictionary like so: {'definedform': userinput, ...}. Is this correct?
I want to create a form in which a user can input data. This data should then be send to a different view, in which the inputted data is rendered with a latex template (and subsequently rendered into a pdf). This works more or less fine if I define the context in the /create_pdf/ view and grab the user input manually. But I suppose there is a nicer way. What I think should work:
def index(request):
if request.method == "POST":
persoform = PersonalForm(request.POST, prefix='personal')
if persoform.is_valid():
content = persoform.cleaned_data()
content = Context(content)
return HttpResponseRedirect('/create_pdf/')
else:
persoform = PersonalForm()
return render(request, 'app/template.html', {'persoform': persoform})
And in my /create_pdf/ view:
def create_pdf(request):
template = get_template('app/latextemplate.tex')
rendered_tpl = template.render(content)
[...]
So, how can I make sure, to pass the data from my index view to my create_pdf view?
EDIT:
Forgot to mention: The error is "'content' not defined". So I understand that the /create_pdf/ view doesn't get content dictionary, but I have no idea how I would make sure that it does.
Put the data in to the session on submit, and pop it out in the second view.
if form.is_valid():
request.session['perso'] = form.cleaned_data
return HttpResponseRedirect('/create_pdf/')
...
def create_pdf(request):
data = request.session.pop('perso'], {})
The Django doc mention that a Model AutoField will not be represented in a form built with a ModelForm.
When editing and saving that form, how should I supposed to know the underlying AutoField id value to save correctly my form data to database?
I know I can inject myself in the edit form an hidden field to know which row has been edited but is there a way Django manage that hidden field or some other mecanism automatically?
Thanks a lot
Etienne
You do that by specifying the instance=<> parameter when you are using ModelForm.
More on this in the documentation here
Example usage of a create/update view:
def myview(request, id=None):
if id:
obj_to_edit = MyModel.objects.get(id=1)
form = MyForm(instance=obj_to_edit)
else:
obj_to_edit = None
form = MyForm()
if request.method == 'POST':
if id: #update
form = MyForm(request.POST, instance=obj_to_edit)
else: #create
form = MyForm(request.POST)
#rest of the code
and the URL would have something like:
url(r'/blah/create/', 'myview'),
url(r'/blah/edit/(?P<id>[\d+])/', 'myview')
Now, django understands that it needs to edit rather than create new objects.
Also note that if you are using forms.Form, you would have to manually query for the unique fields, or inject the hidden id field as you have mentioned.
Usually when you're editing a form the specific instance that you want to edit will be identified in your URL using either the primary key or a slug field, e.g:
www.example.com/model/edit/6/
or
www.example.com/model/edit/object_slug/
You would then set up your urls.py to pass that parameter to your view, where you would use the example provided by karthkir (I'll use the primary as the example from here)
urls.py
urlpatterns = patterns('',
url(regex=r'^model/edit/(?P<pk>\d+)/$', 'myapp.views.myview', name='add_customer'),
)
views.py
def myview(request, pk):
obj_to_edit = MyModel.objects.get(id=pk)
...
I have some question:
I use django form, and fields like MultipleChoiceField
in view.py I clean data and get GET URL like this
http://localhost:8000/?category=&style=&sex=&brand=ASICS&brand=Be+Positive&low_price=&high_price=
Give me advise, can I regroup brand field and hide empty.
I want getting something like this:
http://localhost:8000/?brand=1+2
And else one question:
How can I set empty value(empty_label) for forms.ModelMultipleChoiceFIeld
forms.py:
brand = forms.MultipleChoiceField(required=False,
widget=forms.SelectMultiple(attrs={'size':1})
)
def __init__(self,app_label=None, *args, **kwargs):
super(Search, self).__init__(*args, **kwargs)
self.fields['brand'].choices = [('', 'All brands')]+[(brand.name, brand) for brand in Brand.objects.all() ]
views.py:
if request.method == 'GET' and request.GET:
form = SearchForm(app_label, request.GET)
if form.is_valid():
brands = form.cleaned_data['brand']
kwargs.update({"brand__name__in": brands})
This is how the browser submits multiple data. It's part of the HTML specification, trying to change it would be folly and technically I can't understand why you would try to care about how your url GET data looks.
That being said, if you want to change the way it submits you'll need javascript to transform the data on form submit. Django has nothing to do with the matter.
Using jQuery for example:
$('#form').submit(function(){
//Get form data
//Transform into my custom set of vars
//Redirect to form's ACTION with my querystring appended.
});
Please keep in mind you will not get any automatic parsing of the values on the Django side. Normally it would turn it into a list for you, but now you're responsible for parsing the 'value+value+value' yourself.
For empty label in forms you could do this -
class SomeForm(forms.Form):
h=forms.CharField(label=u'',widget=forms.TextInput(attrs={'value':'Search'}))
By keeping label as '', you get the label as empty. The attrs are basically the HTML attributes of the form text field.
UPDATE: I didn't understand the first part of your Q, elaborate...
In Django, how do I associate a Form with a Model so that data entered into the form are inserted into the database table associated with the Model? How do I save that user input to that database table?
For example:
class PhoneNumber(models.Model):
FirstName = models.CharField(max_length=30)
LastName = models.CharField(max_length=30)
PhoneNumber = models.CharField(max_length=20)
class PhoneNumber(forms.Form):
FirstName = forms.CharField(max_length=30)
LastName = forms.CharField(max_length=30)
PhoneNumber = forms.CharField(max_length=20)
I know there is a class for creating a form from the the model, but even there I'm unclear on how the data actually gets to the database. And I'd like to understand the inner workings before I move on to the time-savers. If there is a simple example of how this works in the docs, I've missed it.
Thanks.
UPDATED:
To be clear -- I do know about the ModelForm tool, I'm trying to figure out how to do this without that -- in part so I can better understand what it's doing in the first place.
ANSWERED:
With the help of the anwers, I arrived at this solution:
Form definition:
class ThisForm(forms.Form)
[various Field assignments]
model = ThisModel()
Code in views to save entered data to database:
if request_method == 'POST':
form = ThisForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.items():
setattr(form.model, key, value)
form.model.save(form.model)
After this the data entered in the browser form was in the database table.
Note that the call of the model's save() method required passage of the model itself as an argument. I have no idea why.
CAVEAT: I'm a newbie. This succeeded in getting data from a browser to a database table, but God only knows what I've neglected or missed or outright broken along the way. ModelForm definitely seems like a much cleaner solution.
Back when I first used Forms and Models (without using ModelForm), what I remember doing was checking if the form was valid, which would set your cleaned data, manually moving the data from the form to the model (or whatever other processing you want to do), and then saving the model. As you can tell, this was extremely tedious when your form exactly (or even closely) matches your model. By using the ModelForm (since you said you weren't quite sure how it worked), when you save the ModelForm, it instantiates an object with the form data according to the model spec and then saves that model for you. So all-in-all, the flow of data goes from the HTML form, to the Django Form, to the Django Model, to the DB.
Some actual code for your questions:
To get the browser form data into the form object:
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
model.attr = form.cleaned_data['attr']
model.attr2 = form.cleaned_data['attr2']
model.save()
else:
form = SomeForm()
return render_to_response('page.html', {'form': form, })
In the template page you can do things like this with the form:
<form method="POST">
{{ form.as_p }}
<input type="submit"/>
</form>
That's just one example that I pulled from here.
I'm not sure which class do you mean. I know that there were a helper, something like form_for_model (don't really remember the exact name; that was way before 1.0 version was released). Right now I'd it that way:
import myproject.myapp.models as models
class PhoneNumberForm(forms.ModelForm):
class Meta:
model = models.PhoneNumber
To see the metaclass magic behind, you'd have to look into the code as there is a lot to explain :]. The constructor of the form can take instance argument. Passing it will make the form operate on an existing record rather than creating a new one. More info here.
I think ModelForm.save documentation should explain it. With its base class (Form) you would need to use the Form.cleaned_data() to get the field values and set them to appropriate Model fields "by hand". ModelForm does all that for you.
The Django documentation is pretty clear on this subject. However, here is a rough guide for you to get started: You can either override the form's save method or implement that functionality in the view.
if form.is_valid() # validation - first the fields, then the form itself is validated
form.save()
inside the form:
def save(self, *args, **kwargs):
foo = Foo()
foo.somefield = self.cleaned_data['somefield']
foo.otherfield = self.cleaned_data['otherfield']
...
return foo.save()