I created an update form, the form has 2 time field and 2 date time field, once click on submit even nothing change, I got an error "'datetime.datetime' object has no attribute 'strip'".
but there is no error when creating a new object for the same model .
modles:
time_start=models.DateTimeField(blank=True,null=True)
htime_start=models.TimeField(blank=True,null=True)
time_end = models.DateTimeField(blank=True, null=True)
htime_end=models.TimeField(blank=True,null=True)
time_require=models.DateTimeField(blank=True,null=True)
machine=models.ForeignKey(Machine,null=True, on_delete=models.SET_NULL, blank=True)
forms:
class AssignTimeForProjects(forms.ModelForm):
title = forms.CharField(disabled=True)
owner=forms.CharField(disabled=True)
time_require=forms.TimeField(disabled=True)
class Meta:
model = tb_order
# fields='__all__'
fields = ['title', 'owner', 'grade', 'quantity',
'time_require','htime_start','color',
'mould','time_start','time_end', 'htime_end' ,'machine']
def __init__(self, *args, **kwargs):
super(AssignTimeForProjects, self).__init__(*args, **kwargs)
self.fields["time_end"] = JalaliDateField(label=('تاریخ اتمام'), widget=(AdminJalaliDateWidget))
self.fields["time_start"] = JalaliDateField(label=('تاریخ شروع'), widget=(AdminJalaliDateWidget))
Html:
<label>{{ form.htime_start.label}}</label>
{% render_field form.htime_start type="time" class+="form-control timepicker" autocomplete="off" %}
<br>
<label>{{ form.time_end.label}}</label>
{% render_field form.time_end class+="form-control" autocomplete="off" %}
<br>
<label>{{ form.htime_end.label}}</label>
{% render_field form.htime_end type="time" class+="form-control" autocomplete="off" %}
Related
this is my code and I try to show the label but it is not displaying
this is my form file
forms.py
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
this is my views file and the function for this form
views.py
def project(request, pk):
projectObj = Project.objects.get(id=pk)
form = ReviewForm()
context = {
'project': projectObj,
'form': form
}
return render(request, 'projects/single-project.html', context)
this is the model for the review section
models.py
class Review(models.Model):
VOTE_TYPE = (
('up', 'Up Vote'),
('down', 'Down Vote')
)
owner = models.ForeignKey(Profile, on_delete = models.CASCADE, null=True)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
body = models.TextField(null=True, blank=True)
value = models.CharField(max_length=200, choices=VOTE_TYPE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default = uuid.uuid4, unique=True, primary_key=True, editable=False)
class Meta:
# every user can only have single comment on each project
unique_together = [['owner', 'project']]
def __str__(self):
return self.value
and the html file to display the form
html file
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
I try to show form.label but it is not displaying
the label is contained in the label_tag property in the field:
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label_tag}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
Are you sure for your labels property of Meta class of ModelForm, i do not known this property. You probably need to redefine your field with label you want to, or update field label in the init function of your form.
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
I have difficulties saving 2 forms within one view the only first one is saving but I cant figure out how to save the second one. Here is my code and issue :
models.py
class Office(models.Model):
name = models.CharField(max_length=100,null=True)
Address = models.ForeignKey(Address, on_delete=models.CASCADE, related_name='officeAddress',blank=True,null=True)
def __str__(self):
return self.name
class Address(models.Model):
address_line = models.CharField(max_length=60, blank=True)
address_line2 = models.CharField(max_length=60, blank=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name='District')
province=ChainedForeignKey(Province,chained_field="country",chained_model_field=
"country",show_all=False,auto_choose=True,sort=True)
district=ChainedForeignKey(District,chained_field="province",
chained_model_field="province",show_all=False,auto_choose=True,sort=True)
class Meta:
verbose_name = "Address"
verbose_name_plural = "Addresses"
forms.py
class OfficeModelForm(BSModalModelForm):
class Meta:
model = Office
fields = ['name']
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['address_line','address_line2','country','province','district']
views.py
class OfficeCreateView(BSModalCreateView):
form_class = OfficeModelForm
second_form_class = AddressForm
template_name = 'settings/create_office.html'
success_message = 'Success: Office was created.'
success_url = reverse_lazy('company:office-list')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['address'] = self.second_form_class
return context
create_office.html
{% load static i18n %}
{% load widget_tweaks %}
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ address.media.js }}
<div class="modal-body">
<div class="form-group">{% render_field form.name %}</div>
<div class="form-group">{% render_field address.address_line %}</div>
<div class="form-group">{% render_field address.address_line2 %}</div>
<div class="form-group">{% render_field address.country %}</div>
<div class="form-group">{% render_field address.province %}</div>
<div class="form-group">{% render_field address.district %}</div>
<button class="btn btn-primary ms-auto" type="submit">{% trans "Create new office" %}</button>
</div>
</form>
I think I need first to save the address then use the address.id as a foreign key for office but I don't know how to do this in CBV.
Thanks for your help...
You should change models base names. Example:
class OfficeCreateView(CreateView) instead class OfficeCreateView(BSModalCreateView)
or
class OfficeModelForm(form.ModelForm) instead class OfficeModelForm(BSModalModelForm)
I am trying to render a Django model form using the below model. The problem is one of the model field is a JSONField. This is a list of length 1 having some JSON data. When I render the model form, the number field renders the list without any issues. But I want to extract the phone value from the JSON inside the list and render it. I have tried extracting it in the template but it is not working as intended.
How can I extract the phone value from the JSON and render it in the form? As example, when I render the data for id 1 using my view, I should see 'Client_1' in the name field and '1234567890' in the number field.
I am using Django 3.1 and using Django Crispy Forms to render the model form.
Data as seen client table in db:
id name number
1 Client_1 [{'type': 'mobile', 'phone': '1234567890'}]
2 Client_2 [{'type': 'mobile', 'phone': '3334445555'}]
3 Client_3 [{'type': 'mobile', 'phone': '9876543210'}]
models.py:
class Client(models.Model):
name = models.TextField()
number = models.JSONField(blank=True, null=True)
forms.py:
from .models import Client
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = '__all__'
clients.html template:
{% load crispy_forms_tags %}
<form method="POST">
<div class="form-row">
<div class="form-group col-md-6">
{{ form.name | as_crispy_field }}
</div>
<div class="form-group col-md-6">
{% for item in form.number %}
{{ item.0.phone | as_crispy_field }}
{% endfor %}
</div>
</div>
</form>
views.py:
def clients(request, pk):
instance = Client.objects.get(pk=pk)
if request.method == 'POST':
form = ClientForm(request.POST, instance=instance)
if form.is_valid():
form.save()
else:
form = ClientForm(instance=instance)
return render(request, 'clients.html', {'form': form})
You need add fields dynamically to your form, here is a working example :
class ClientForm(forms.ModelForm):
def __init__(self, *args, instance=None, **kwargs):
super(ClientForm, self).__init__(*args, instance=instance, **kwargs)
if instance:
for index, obj in enumerate(instance.number):
self.fields[f'phone_{index}'] = forms.CharField(initial=obj.get('phone', ''))
def save(self, commit=True):
for index, obj in enumerate(self.instance.number):
obj['phone'] = self.cleaned_data.get(f'phone_{index}', '')
return super(ClientForm, self).save(commit=commit)
class Meta:
model = Client
fields = ['name']
Your template should then be :
{% load crispy_forms_tags %}
<form method="POST">
<div class="form-row">
<div class="form-group col-md-6">
{{ form.name | as_crispy_field }}
</div>
<div class="form-group col-md-6">
{{ form.phone_0 | as_crispy_field }}
</div>
</div>
</form>
NB : If you alway store your phones in a list, you should set a default to your JsonField :
class Client(models.Model):
name = models.TextField()
number = models.JSONField(default=list)
EDITS AVAILABLE BELOW!
My goal:
Category1
----Option1
----Option2
--Option3
Category2
----Option1
----Option2
etc.
I have a parent model (Venue) and a child model (Amenity). A venue can have many amenities.
while configuring my initial data and presenting it with {{form.as_p}} everything works as expected.
But when I try to render my own custom form, so that I can apply a loop, It doesn't pre-populate them.
Here is my template:
<form method="POST" class="ui form">
{% csrf_token %}
{% for category in categories %}
<h4 class="ui horizontal divider header">
<i class="list icon"></i>
{{category.category}}
</h4>
<p class="ui center aligned text"><u>{{category.description}}</u></p>
{% for amenity in category.amenity_set.all %}
<div class="inline field">
<label for="choices_{{amenity.id}}"></label>
<div class="ui checkbox">
<input id="choices_{{amenity.id}}" type="checkbox" value="{{amenity.id}}" name="choices">
<label><span data-tooltip="{{amenity.description}}" data-position="top left">{{amenity}}</span></label>
</div>
</div>
{% endfor %}
{% endfor %}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
my ModelForm:
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.CheckboxSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
and my views.py:
class AddAmenitiesView(LoginRequiredMixin, CreateView):
"""
AddAmenitiesView is the view that prompts the user to select the amenities of their venue.
"""
model = Venue
form_class = AmenitiesForm
template_name = 'venues/add_amenities.html'
def parent_venue(self):
"""
returns the parent_venue based on the kwargs
:return:
"""
parent_venue = Venue.objects.get(id=self.kwargs["venue_id"])
return parent_venue
def get_initial(self):
initial = super().get_initial()
initial['choices'] = self.parent_venue().amenity_set.all()
return initial
def form_valid(self, form):
venue = Venue.objects.get(id=self.kwargs['venue_id'])
form.instance = venue
# form.instance.owner = self.request.user
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["parent_venue"] = self.parent_venue()
context["categories"] = AmenitiesCategory.objects.all()
return context
def get_success_url(self):
return reverse('add-amenities', kwargs={'venue_id': self.object.id,})
I suppose it has to do with my template since rendering the form normally, it does prepopulate the model.
Thank you for taking the time!
EDIT:
With Raydel Miranda's answer below I managed to edit the templates for how the form gets presented:
forms.py:
class CustomAmenitiesSelectMultiple(CheckboxSelectMultiple):
"""
CheckboxSelectMultiple Parent: https://docs.djangoproject.com/en/2.1/_modules/django/forms/widgets/#CheckboxSelectMultiple
checkbox_select.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_select.html
multiple_input.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/multiple_input.html
checkbox_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_option.html
input_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/input_option.html
"""
template_name = "forms/widgets/custom_checkbox_select.html"
option_template_name = 'forms/widgets/custom_checkbox_option.html'
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=CustomAmenitiesSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
custom_checkbox_select.html:
{% with id=widget.attrs.id %}
<div class="inline field">
<div {% if id %} id="{{ id }}" {% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}" {% endif %}>
{% for group, options, index in widget.optgroups %}{% if group %}
<div>
{{ group }}
<div>
{% if id %} id="{{ id }}_{{ index }}" {% endif %}>{% endif %}{% for option in options %}
<div class="checkbox">{% include option.template_name with widget=option %}</div>
{% endfor %}{% if group %}
</div>
</div>
{% endif %}{% endfor %}
</div>
</div>
{% endwith %}
custom_checkbox_option.html :
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>
As requested, also my models.py:
class TimeStampedModel(models.Model):
"""
An abstract base class model that provides self-updating
"created" and "modified" fields.
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class VenueType(TimeStampedModel):
type = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.type
class Venue(TimeStampedModel):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
type = models.ForeignKey(VenueType, on_delete=models.CASCADE)
total_capacity = models.PositiveIntegerField(default=0)
description = models.TextField(blank=False)
contact_number = PhoneNumberField(blank=True)
contact_email = models.EmailField(blank=True)
published = models.BooleanField(default=False)
def __str__(self):
return self.name
class AmenitiesCategory(TimeStampedModel):
category = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.category
class Amenity(TimeStampedModel):
category = models.ForeignKey(AmenitiesCategory, on_delete=models.CASCADE)
venues = models.ManyToManyField(Venue, blank=True)
space = models.ManyToManyField(Space, blank=True)
name = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.name
class Meta:
ordering = ['category']
You said while configuring my initial data and presenting it with {{form.as_p}} everything works as expected, if so, use {{ form.choices }} in order to render that field.
<form method="POST" class="ui form">
{% csrf_token %}
{{form.choices}}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
Then, what you need is have a custom CheckboxSelectMultiple with its own template (in case you want a custom presentation to the user), and use it in your form:
Custom CheckboxSelectMultiple could be:
class MyCustomCheckboxSelectMultiple(CheckboxSelectMultiple):
template_name = "project/template/custom/my_checkbox_select_multiple.html"
And in the form:
class AmenitiesForm(ModelForm):
# ...
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.MyCustomCheckboxSelectMultiple)
# ...
How to implement the template my_checkbox_select_multiple.html, is up to you.
If you're using some Django prior to 1.11, visit this link to learn about a others things you've to do in order to customize a widget template.
Django widget override template
Hope this help!
I'm getting an issue with my Django form validation. I would like to display form errors and make all fields required. I don't know why my fields can accept blank while blank is not defined in my model file.
This is my model :
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
first_name = models.CharField(max_length=70, verbose_name=_('first name'), null=False)
last_name = models.CharField(max_length=70, verbose_name=_('last name'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('customer')
verbose_name_plural = _('customer')
def __str__(self):
return f"{self.email}"
This is my form :
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')
for key in self.fields:
self.fields[key].required = True
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')}),
}
You can find here my view with Django CBV :
class HomeView(CreateView):
""" Render the home page """
template_name = 'app/index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
kwargs['document_list'] = Document.objects.all().order_by('publication__category__name')
return super(HomeView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
if request.method != 'POST':
return HttpResponseRedirect(self.get_success_url())
form = self.form_class(request.POST)
email = request.POST['email']
country_id = request.POST['country']
country = Country.objects.get(id=country_id)
for checkbox in request.POST.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email, document.edqm_id)
Download.objects.create(email=email, country=country, pub_id=checkbox, token=token,
expiration_date=now + timedelta(minutes=10))
if not form.is_valid():
print('form invalid')
continue
return HttpResponseRedirect(self.get_success_url())
And finally my template :
{% extends "publication/base_backend.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" id="customerform" novalidate>
{% csrf_token %}
<h3>{% trans 'Your information' %}</h3>
<hr>
<div class="col-sm-12 col-md-12 col-lg-12">
{{ form.email|as_crispy_field:"bootstrap" }}
</div>
<br />
<br />
<br />
<br />
<div class="alert alert-info col-sm-12 col-md-12 col-lg-12" role="alert">
<small>{% trans "The fields below are optional if you have already requested a publication:" %}</small>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
{{ form.first_name|as_crispy_field:"bootstrap" }}<br>
{{ form.country|as_crispy_field:"bootstrap" }}
</div>
<div class="col-sm-5 col-md-5 col-lg-5 col-sm-offset-2 col-md-offset-2 col-lg-offset-2">
{{ form.last_name|as_crispy_field:"bootstrap" }}<br>
{{ form.institution|as_crispy_field:"bootstrap" }}
</div>
<div class="col-md-12">
<br />
<br />
</div>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
{% trans 'Cancel' %}
</form>
Issues :
According to required fields, I don't know why my form doesn't display missing values errors when I want to submit it.
I have to display fields as shown in my template because I have to make bootstrap design.
In order to display form errors, I have to write {{form.email.errors}} for example but nothing appears.
Thank you by advance