Django ModelForm initial not working for textarea - python

I have a django ModelForm, I'm trying to populate it with initial values from my views, all fields are populated except for the textarea field. I have no idea why. Any help is appreciated. Thanks!
views.py
name = 'Testing123'
private = True
notes = 'JUST CHECKING'
ctx['header_form'] = NewTemplateForm(initial={'name': name, 'private': private,'notes:': notes})
private is a BooleanField, initial works even for that
name is populated
notes is the only field that isn't being populated.
template.html
I'm rendering the form like this:
{% load widget_tweaks %}
<div class="form-group">
<div class="row" style="margin-bottom: 15px">
<div class="col-lg-6">
<label>{{form.name.label}}</label>
{% render_field form.name class="form-control" required="true" %}
</div>
<div class="col-lg-6" style="margin-top: 23px">
<div class="i-checks"><label> {% render_field form.private type="checkbox" %} <i></i> Make this Template Private </label></div>
</div>
</div>
</div>
<div class="row" style="margin-bottom: 15px">
<div class="col-lg-12">
<label data-error="wrong" data-success="right" for="id_notes">{{form.notes.label}}</label>
{% render_field form.notes class="form-control" %}
</div>
</div>
forms.py
class NewTemplateForm(ModelForm):
class Meta:
model = SalesTemplate
fields = {'name', 'notes', 'private'}
def __init__(self, *args, **kwargs):
super(NewTemplateForm, self).__init__(*args, **kwargs)
self.fields['notes'].widget = forms.Textarea(attrs={'class': 'md-textarea', 'style': 'height: 75px'})

Because there is a typo in your code and you are passing 'notes:' as key instead of 'notes' in this line
ctx['header_form'] = NewTemplateForm(initial={'name': name, 'private': private,
'notes:': notes}) # HERE!

Related

Why I can't save values in database? Django

I want to save my form in database, but save() doesn't work. When I do this, error wasn't showing. At the start, I think problem was in database, but it isn't
views.py
def comments(request):
comments = Comment.objects.all()
form = CommentForm()
context = {"comments": comments, "form": form}
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.avtor = request.user
comment.save()
return HttpResponseRedirect(reverse('comment'))
else:
context["form"] = form
return render(request, "home/comments.html", context)
else:
return render(request, "home/comments.html", context)
And models. So, I think problem yet in views.py. I bad know how function save() is working.
models.py
class Comment(models.Model):
Text = models.TextField(verbose_name='Text')
date = models.DateTimeField(default=timezone.now, verbose_name='date')
avtor = models.ForeignKey(User, verbose_name='avtor', on_delete=models.CASCADE)
def __str__(self):
return 'Comment {} at {}'.format(self.avtor, self.date)
class Meta:
ordering = ["-id"]
forms.py
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ("Text",)
At the last, I want to save avtor, text and Date. Help me please.
<div class="container" style="min-height: 520px;">
<form class="text-light formGroupComm" action="/" method="post">
{% csrf_token %}
{{ form }}
<br>
<button style="width: 6%!important;" class="btn btn-warning mb-5 mt-3 mx-auto" type="submit">submit</button>
</form>
<div class="comments text-dark">
{% for comentPost in comments %}
<div class="commentItem bg-warning my-3" style="border-radius: 40px; padding: 20px;">
<div style="border-bottom: 3px solid black;" class="comTitle mx-3 my-3">{{ comentPost.avtor }}</div>
<div style="" class="comText mx-5">{{ comentPost.Text }}</div>
<div style="" class="comDate mx-3 my-5">{{ comentPost.date|date:"F d, Время: h:i" }}</div>
</div>
{% endfor %}
</div>
</div>
The action attribute specifies where to send the form-data when a form is submitted (https://www.w3schools.com/tags/att_form_action.asp).
So when you put the "/" in there, the form will send the data to the home page (represented by / in html). This means that your data doesn't get to the POST section of your def comments(request) method. When the method is not called, the logical outcome is thus that there isn't a new comment added.
This is the correct code:
<div class="container" style="min-height: 520px;">
<form class="text-light formGroupComm" method="post">
{% csrf_token %}
{{ form }}
<br>
<button style="width: 6%!important;" class="btn btn-warning mb-5 mt-3 mx-auto" type="submit">submit</button>
</form>
<div class="comments text-dark">
{% for comentPost in comments %}
<div class="commentItem bg-warning my-3" style="border-radius: 40px; padding: 20px;">
<div style="border-bottom: 3px solid black;" class="comTitle mx-3 my-3">{{ comentPost.avtor }}</div>
<div style="" class="comText mx-5">{{ comentPost.Text }}</div>
<div style="" class="comDate mx-3 my-5">{{ comentPost.date|date:"F d, Время: h:i" }}</div>
</div>
{% endfor %}
</div>
</div>

How to create dropdown box with forms.ModelForm in Django?

I'm trying to add a dropdown box of choices in my form. What I tried:
from django import forms
from .models import Car
class CarForm(forms.ModelForm):
owner_name = forms.CharField(max_length=100, label='Owner Name', required=True)
car_type = forms.ChoiceField(choices=Car.CarTypes.choices, label='Car Type', required=True)
class Meta:
model = Car
fields = ('owner_name', 'car_type')
It adds the car_type field to the form but it's not a dropdown for some reason (it's a regular empty box you could fill). The CarTypes looks like:
class CarTypes(models.TextChoices):
X = 'some_x'
Y = 'somy_y'
# ...
What could be the reason?
In my Car class I have: car_type = models.CharField(max_length=24, choices=CarTypes.choices, default=CarTypes.X). Could be it? I think CharField makes it empty box. But changing it to ChoiceField ends with: module 'django.db.models' has no attribute 'ChoiceField'. How to solve it?
I tried this approach but it uses a tuple instead of a class. From the example there I see they use tuple of two-value-tuples like (('a','A'),('b','B')) and I'm using class. Could it be the reason?
In my html I have:
<form method="post" class="form-group">
{% csrf_token %}
{% for field in form %}
<div class="form-group col-md-12 mb-3">
<label for="{{ field.label }}">{{ field.label }}</label>
<input type="text" class="form-control" id="{{ field.label }}" name="{{ field.name }}">
</div>
{% endfor %}
<hr class="mb-4">
<button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
</form>
And the Car looks like:
class Car(models.Model):
class CarTypes(models.TextChoices):
X = 'some_x'
Y = 'somy_y'
# ...
owner_name = models.CharField(max_length=100,unique=True)
car_type = models.CharField(max_length=24, choices=CarTypes.choices, default=CarTypes.X)
def __str__(self):
return self.owner_name
You don't need to override your model fields. See Field types - Django Docs
If the model field has choices set, then the form field’s widget will
be set to Select, with choices coming from the model field’s choices.
The following code should do what you want:
forms.py
from django import forms
from .models import Car
class CarForm(forms.ModelForm):
class Meta:
model = Car
fields = ['owner_name', 'car_type']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['owner_name'].widget.attrs.update({"class": "form-control"})
# or iterate over field to add class for each field
for field in self.fields:
self.fields[field].widget.attrs.update({'class':"form-control"})
You can add any html attribute in __init__ method.
html:
<form method="post" class="form-group">
{% csrf_token %}
<div class="form-group col-md-12 mb-3">
<label for="{{ form.owner_name.label }}">{{ form.owner_name.label }}</label>
{{ form.owner_name }}
</div>
<div class="form-group col-md-12 mb-3">
<label for="{{ form.car_type.label }}">{{ form.car_type.label }}</label>
{{ form.car_type }}
</div>
<hr class="mb-4">
<button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
</form>
Or You can use {{ form.as_p }} - Django Docs will render them wrapped in <p> tags
UPDATE
Render form manually:
<form method="post" class="form-group">
{% csrf_token %}
<div class="form-group col-md-12 mb-3">
<label for="{{ form.owner_name.label }}">{{ form.owner_name.label }}</label>
<input type="text" class="form-control" id="{{ form.owner_name.auto_id }}" name="{{ form.owner_name.name }}">
</div>
<div class="form-group col-md-12 mb-3">
<label for="{{ form.car_type.label }}">{{ form.car_type.label }}</label>
<select id="{{ form.car_type.auto_id }}" name="{{ form.car_type.name }}">
{% for value, label in form.fields.car_type.choices %}
<option value="{{ value }}"{% if form.car_type.value == value %} selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<hr class="mb-4">
<button type="submit" class="btn btn-secondary btn-lg btn-block">Submit New Car</button>
</form>
Try to use this method of Choices :-
models.py
choices = [
('choice1', 'choice1'),
('choice2',"choice2"),
('choice3',"choice3")
]
class Car(models.Model):
owner_name = models.CharField(max_length=100,unique=True)
car_type = models.CharField(max_length=24, choices=choices, default='choice1')
def __str__(self):
return self.owner_name
And then don't forget to make migrations
Refer this ---> https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.Field.choices
For Django 3.1, you can achieve this with widgets. Here's how you can get it done:
from django.forms import ModelForm, Select, TextInput
from .models import Car
class CarForm(ModelForm):
class Meta:
model = Car
fields = ('owner_name', 'car_type')
widgets = {
'owner_name': TextInput(),
'car_type': Select(),
}
And Model should look like this:
class Car(models.Model):
choices = [('X':'some_x'), ('Y': 'some_y']
owner_name = models.CharField(max_length=100,unique=True)
car_type = models.CharField(max_length=24, choices=choices, default='some_y')
def __str__(self):
return self.owner_name```

Rendering fields manually---Django

I am learning to program in django and I have a question, I have been reading the django documentation on how to manually render the form fields, and I have not been able to understand and save the data; when I use form.as_p I can get the data to be saved to my database, but when I try to render it manually or separately I can't. Could someone please explain, then I leave the code I am using
models.py
class CrearUsuario(CreateView):
model = Proveedor
form_class = ProveedorForm
template_name = 'contratacion/formsuser.html'
success_url = reverse_lazy('proveedor')
forms.py
class ProveedorForm(ModelForm):
class Meta:
model = Proveedor
fields = '__all__'
forms.user.html
<form method='POST'>{% csrf_token %}
<div class="row">
<div class="col">
<div class="form-group">
<label class="col-lg-2 control-label">Razon Social</label>
<div class="col-md-3">
{{form.razon_social}}
</div>
</div>
</div>
<div class="col">
<div class="form-group">
<label class="col-lg-2 control-label">Sigla</label>
<div class="col-md-3">
{{form.sigla}}
</div>
</div>
</div>
</div>

Handle POST/GET forms with Django and Bootstrap Modal

I'm using different forms (POST and GET) in my Django web application and Bootstrap modal to do that.
In my template, user can choose some documents, submit the list of documents which is picked up to a Django form (CustomerForm) in my modal. This CustomerForm lets to send an email with user informations previously filled.
My CustomerForm looks like this :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by('name')
self.fields['email'].required = True
self.fields['first_name'].required = True
self.fields['last_name'].required = True
self.fields['country'].required = True
self.fields['institution'].required = False
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
I have views.py file :
class HomeView(CreateView, FormView):
""" Render the home page """
template_name = 'index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
# display some things
# ...
if "DocumentSelected" in self.request.GET:
checkbox_list = self.request.GET.getlist('DocumentChoice')
document = Document.objects.filter(id__in=checkbox_list)
kwargs['selected_document'] = document
return super(HomeView, self).get_context_data(**kwargs)
def form_valid(self, form):
email = form.cleaned_data['email']
country = form.cleaned_data['country']
for checkbox in self.request.GET.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email)
now = timezone.now()
expiration = now + settings.DOWNLOAD_VALIDITY
Download.objects.create(email=email, country=country, doc_id=checkbox, token=token,
expiration_date=expiration)
self.send_email(email, document.upload, document.publication.title, token)
return super(HomeView, self).form_valid(form)
And finally in my HTML template you can find something which looks like this :
<form method="GET" action="">
<!-- Table with checkboxes - User has to check wanted objects -->
<div class="row">
<div class="col-md-offset-3 col-md-4">
<input type="submit" class="btn btn-default" name="DocumentSelected" value="{% trans 'Save document(s)' %}"/>
<input type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" value="{% trans 'Send document(s)' %}"/>
</div>
</div>
</form>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">{% trans 'Your informations' %}</h4>
</div>
<form method="post" action="" novalidate>
{% csrf_token %}
<div class="modal-body">
<div class="row">
<div class="col-md-12">
{{ form.email|as_crispy_field }}
</div>
</div>
<div class="row">
<div class="col-md-6">
{{ form.first_name|as_crispy_field }}
</div>
<div class="col-md-6">
{{ form.last_name|as_crispy_field }}
</div>
</div>
<div class="row">
<div class="col-md-6">
{{ form.country|as_crispy_field }}
</div>
<div class="col-md-6">
{{ form.institution|as_crispy_field }}
</div>
</div>
</div>
<div class="modal-header">
<h4 class="modal-title">{% trans 'Your cart' %}</h4>
</div>
<div class="model-body">
{% for element in selected_document|dictsort:'format' %}
<!-- Display wanted objects -->
{% endfor %}
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-default" data-dismiss="modal" value="{% trans 'Send' %}"/>
</div>
</form>
</div>
</div>
</div>
Process :
This is the needed way :
User has to check one or multiple documents
User submits the choice and a modal containing CustomerForm is opening.
User fills CustomerForm fields and see in Cart part his document(s)
User submits the CustomerForm and an email is sent with previous informations/documents.
I think my method could work, but I don't overcome to call form_valid function and I would like to write correctly this class.
There is certainly ugly issues and I apologize by advance. But this is not the best way to improve myself and doesn't reproduce these issues ? ;)
Thanks !
EDIT :
I made something which seems to work. I removed data-dismiss="modal" from my modal submit button. I read that this attribute closed my modal and didn't post any form !
Finally, is it a good way to do what I did ?
Is it possible to replace both buttons Save documents and Send documents by an unique button which get documents and open the modal ?
I made something which seems to work. I removed data-dismiss="modal" from my modal submit button.
Previously :
<input type="submit" class="btn btn-default" data-dismiss="modal" value="{% trans 'Send' %}"/>
Now :
<input type="submit" class="btn btn-default" value="{% trans 'Send' %}"/>
It works now !
It was because data-dismiss="modal" closed the modal and I didn't know that.

Django Form Field Custom attribute assignment and use in template

I am trying to generate a form dynamically and want to assign indentation of form fields. I am trying to assign an custom attribute offset to forms.CharField in subclass. I plan to use this logic to create a form dynamically from an xml file, where the fields would be indented based on the depth of the node.
I am unable to retrieve the value of offset while rendering the template and hence unable to assign the margin-left style parameter. The final html output is also shown.
Can someone please help. I have searched some other answers on this site where it appears that arbitrary attributes can be assigned and retrieved in template. e.g.as in thread here where an arbitrary label_class attribute is assigned
My forms.py file :
class MyCharField(forms.CharField):
def __init__(self, *args, **kwargs):
self.offset = kwargs.pop('offset', 0)
super(MyCharField, self).__init__(*args, **kwargs)
class MyDynamicForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MyDynamicForm, self).__init__(*args, **kwargs)
self.fields["Field_A"] = MyCharField(label="Input A", offset="5")
self.fields["Offset_Field_B"] = MyCharField(label="Input B", offset="50")
My Views.py looks like this:
class MyDynamicView(View):
template_name = 'demo/myform.html'
form_class = MyDynamicForm
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
My template file using bootstrap looks like this:
{% extends 'demo/base.html' %}
{% load bootstrap3 %}
{% block content %}
<form role="form" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: {{field.offset}}px" for="{{ field.name }}">{{ field.label}}</label>
<div class="col-md-9">
<input class="form-control" id="id_{{field.name}}" name="{{ field.name }}" placeholder="{{field.label}}" style="margin-left:{{field.offset}}px" title="" required="" type="text"/>
</div>
</div>
{% endfor %}
{% buttons submit='OK' reset='Cancel' layout='horizontal' %}{% endbuttons %}
</form>
{% endblock %}
The html output is:
<form role="form" method="post">
<input type='hidden' name='csrfmiddlewaretoken' value='lTy0rc2r9KNiNNPosUoriUlNzYBpgoVpael1MYLOczFECO7H7LXdES6EGBhUoXx0' />
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: px" for="Field_A">Input A</label>
<div class="col-md-9">
<input class="form-control" id="id_Field_A" name="Field_A" placeholder="Input A" style="margin-left:px" title="" required="" type="text"/>
</div>
</div>
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: px" for="Offset_Field_B">Input B</label>
<div class="col-md-9">
<input class="form-control" id="id_Offset_Field_B" name="Offset_Field_B" placeholder="Input B" style="margin-left:px" title="" required="" type="text"/>
</div>
</div>
<div class="form-group"><label class="col-md-3 control-label"> </label><div class="col-md-9"><button class="btn btn-default" type="submit">OK</button> <button class="btn btn-default" type="reset">Cancel</button></div></div>
</form>
It not necessary to instantiate from CharField for that. Probably such initialization of the field in form will be enough for you:
field_a = forms.CharField('Input_A',
widget=forms.TextInput(attrs={'placeholder': 'Input_A', 'style': 'margin-left: 50px'}))

Categories

Resources