Checkboxes and Radio buttons in Django ModelForm - django

Welcome friends,
I'm a newbie in Django. I need your help. Seriously.
I want to add checkboxes and radio button in my form.
Any help will be appreciated.
models.py
from django.db import models
from shop.models import Product
class Order(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
address = models.CharField(max_length=250)
postal_code = models.CharField(max_length=20)
city = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
class Meta:
ordering = ('-created',)
def __str__(self):
return 'Order {}'.format(self.id)
def get_total_cost(self):
return sum(item.get_cost() for item in self.items.all())
forms.py
from django import forms
from .models import Order
class OrderCreateForm(forms.ModelForm):
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'address', 'postal_code', 'city']
create.html
{% extends "shop/base.html" %}
{% block title %}
Checkout
{% endblock %}
{% block content %}
<h1>Checkout</h1>
<form action="." method="post" class="order-form">
{{ form.as_p }}
<p><input type="submit" value="Place order"></p>
{% csrf_token %}
</form>
{% endblock %}
Any suggestions are welcome.Please help.
UPDATE
How to add select option ?

you can do something like this
CHOICES=[('item1','item 1'),
('item2','item 2')]
class OrderCreateForm(forms.ModelForm):
postal_code = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect())
....
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'address', 'postal_code', 'city']
similarly, you can do for the other field also
and for checkbox, you can define it as a BooleanFileld and you can use
{{ form.paid }}
in you template.

The form will be rendered with the field types you define in the model:
BooleanField is rendered as a checkbox, paid in your case.
ChoiceField can be rendered as radio buttons with the appropiate widget.
You can redefine the widgets in class OrderCreateForm:
CHOICES = [('option1','label 1'), ('option2','label 2')]
some_field = forms.ChoiceField(choices=CHOICES,widget=forms.RadioSelect())

Related

Django forms - how to add labels inside boxes?

I have simple django- form:
class ContactUsForm(forms.ModelForm):
class Meta:
model = Contact
fields = ('subject', 'email', 'message')
widgets = {'time': forms.HiddenInput()}
labels = {
'subject': 'my_subject',
'email': 'my_email',
'message': 'my_message',
}
Model:
class Contact(models.Model):
email = models.EmailField(max_length=100)
subject = models.CharField(max_length=100)
message = models.TextField()
time = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.message
And html:
<h2 class="mb-5">Contact</h2>
{% load crispy_forms_filters static %}
<form method="POST" class="post-form">{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-outline-secondary">Send</button>
</form>
How to remove labels above boxes and put it inside? Is it possible to do it with crispy?
Try this !
class ContactUsForm(forms.ModelForm):
subject = forms.CharField(label='Subject', widget=forms.TextInput(attrs={'placeholder': 'Subject'}))
email = forms.EmailField(label='Email', widget=forms.TextInput(attrs={'placeholder': 'Email'}))
message = forms.TextField(label='Message', widget=forms.TextInput(attrs={'placeholder': 'Message'}))
class Meta:
model = Contact
fields = ('subject', 'email', 'message')
This feature is not available in crispy forms. The question below shows a dry way of achieving this using the init method
Use field label as placeholder in django-crispy-forms

django form rendering out of order

I'm learning how to use ModelForms and I've successfully gotten the form to render, but the fields aren't showing up in the order that I'd like them to. I tried changing the order in forms.py and that had no effect. How can I go about changing the order; for instance, putting title at the top instead of the bottom and making the picture field second to last instead of second?
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=150)
price = models.CharField(max_length=100)
body = models.TextField()
pub_date = models.DateTimeField(null=True)
author = models.ForeignKey(User, null=True)
category = models.CharField(max_length=150, null=True)
picture = models.ImageField(upload_to='ad_pictures', default='')
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Post
from django.contrib.auth.models import User
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = {
'title',
'body',
'category',
'price',
'picture',
}
views.py
def create(request):
form = PostForm(request.POST or None, request.FILES or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return render(request, 'classifieds/latest-ads.html')
else:
form = PostForm()
args = {'form': form}
return render(request, 'classifieds/create-post.html', args)
create.html
{% extends 'base.html' %}
{% block head %}
<!-- {% load static %}
<link rel="stylesheet" href="{% static 'accounts/login.css' %}" type="text/css"> -->
<title>Create Post</title>
{% endblock %}
{% block body %}
<div class="container"><br>
<form method="POST" action='' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" value="submit">Submit</button>
</form>
</div>
{% endblock %}
I'd like to point out that in this video the uploader is able to manipulate the order and have the changed render in the template but I cannot.
Any insight is greatly appreciated.
No need for field_order = ['price', 'title', 'body', 'category', 'picture']
Just replace {} with () for fields
so you should have:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = (
'title',
'body',
'category',
'price',
'picture',
)

NOT NULL constraint failed: cars_car.owner_id

I was able to render the form onto the html, input data and submit it but i got a NOT NULL constraint failure. Isn't the owner assigned to its respective owners when as i have indicated in my views? i do not know what is wrong here please help!
Models
class Car(models.Model):
owner = models.ForeignKey('auth.User', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
model = models.CharField(max_length=100)
description = models.TextField()
image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now_add=False)
mileage = models.IntegerField()
open_market_value = models.DecimalField(max_digits=12, decimal_places=2)
depreciation = models.DecimalField(max_digits=10, decimal_places=2)
down_payment = models.DecimalField(max_digits=10, decimal_places=2)
road_tax = models.DecimalField(max_digits=8, decimal_places=2)
installment = models.DecimalField(max_digits=8, decimal_places=2)
objects = models.Manager()
def __str__(self):
return self.name
Views
class CarCreate(CreateView):
model = Car
fields = [
'name', 'model',
'description', 'image',
'updated', 'mileage',
'open_market_value', 'depreciation',
'down_payment', 'road_tax',
'installment']
template_name = 'cars/create_car.html'
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
HTML
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<!-- Default form contact -->
<form action="{% url 'cars:create' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form | crispy}}
<input type="submit" value="save">
</form>
<!-- Default form contact -->
{% endblock %}
Your model has a foreign key to the User model from 'django.auth'. While you are trying to save the object of 'Car' model as there was no object mentioned for the 'owner' field of the model, it is showing the error. So, you might want to explicitly mention it.
You can do something like this. Assuming that you have 'CarForm', a model form for you 'Car' model.
user = request.user
car_form = CarForm(request.POST)
if car_form.is_valid():
car = car_form.save(False)
car.owner = user
car.save()
This is most likely because owner is a required field in your model Car but you have not included it in the fields in your CreateView.

Building dynamic forms from models

I have the following model in models.py
class TProfiles(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
first_name = models.CharField(max_length=45, blank=True)
surname = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=45, blank=True)
class Meta:
managed = False
db_table = 'profiles'
And in my template I want to produce a form based on the model attributes. Is there a way of looping through them dynamically?
register.html
{% block content %}
<form enctype="multipart/form-data" action="" method="post">
<!-- Loop through model attributes here -->
</form>
{% endblock %}
in models.py add:
class TProfilesForm(ModelForm):
class Meta:
model = TProfiles
fields = ['first_name', 'surname', 'email']
And in views.py create form like this:
form = TProfilesForm()
Then pass it to template like this:
return render_to_response("register.html", {
"form": form,
})
And in template:
{% for field in form %}
{{ field.label_tag }} {{ field }}
{% endfor %}
Also you can find all about ModelForm here

Django Dropdown populate from database

If I pass items to the template through the view, and I want the user to select one of the values that gets submitted to a user's record, I would only have dun a for loop in the template right?
What would that look like?
In the template:
<form method="POST"
<select>
</select>
</form>
Model:
class UserItem(models.Model):
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
class Item(models.Model):
name = models.CharField(max_length = 50)
condition = models.CharField(max_length = 50)
View:
def selectview(request):
item = Item.objects.filter()
form = request.POST
if form.is_valid():
# SAVE
return render_to_response (
'select/item.html',
{'item':item},
context_instance = RequestContext(request)
)
If I understood your need correctly, you can do something like:
<form method="POST">
<select name="item_id">
{% for entry in items %}
<option value="{{ entry.id }}">{{ entry.name }}</option>
{% endfor %}
</select>
</form>
By the way, you should give the name items instead of item, since it's a collection (but it's just a remark ;)).
Doing so, you will have a list of all the items in the database.
Then, in the post, here what you need to do:
def selectview(request):
item = Item.objects.all() # use filter() when you have sth to filter ;)
form = request.POST # you seem to misinterpret the use of form from django and POST data. you should take a look at [Django with forms][1]
# you can remove the preview assignment (form =request.POST)
if request.method == 'POST':
selected_item = get_object_or_404(Item, pk=request.POST.get('item_id'))
# get the user you want (connect for example) in the var "user"
user.item = selected_item
user.save()
# Then, do a redirect for example
return render_to_response ('select/item.html', {'items':item}, context_instance = RequestContext(request),)
Of course, don't forget to include get_object_or_404
Here is a more dry way to do this in 2021:
models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateField(null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
urls.py
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.PersonListView.as_view(), name='person_changelist'),
path('add/', views.PersonCreateView.as_view(), name='person_add'),
path('<int:pk>/', views.PersonUpdateView.as_view(), name='person_change'),
]
views.py
from django.views.generic import ListView, CreateView, UpdateView
from django.urls import reverse_lazy
from .models import Person
class PersonListView(ListView):
model = Person
context_object_name = 'people'
class PersonCreateView(CreateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
class PersonUpdateView(UpdateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
HTML
{% extends 'base.html' %}
{% block content %}
<h2>Person Form</h2>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Save</button>
Nevermind
</form>
{% endblock %}
RESULT:
Reference: https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html