Reputation: 472
I am new to Django and still learning. Currently, I have a running code below which allows me to input data but I am unable to POST it to DB. I am not sure what I've done wrong.
Model
class ManHour(models.Model):
station_choices = (
('alpha','A'),
('beta', 'B'),
('gamma','G'),
)
station = models.CharField(
max_length=3,
choices=station_choices,
)
date = models.DateTimeField(auto_now=True)
ops_1 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
ops_2 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
ops_3 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
Form
from django import forms
from webapp.models import ManHour
class InputForm(forms.ModelForm):
class Meta:
model = ManHour
fields = ['station', 'ops_1', 'ops_2', 'ops_3']
Views
def form_page(request):
if request.method == 'POST':
properties_Form = InputForm(request.POST)
if properties_Form.is_valid():
properties_Form.save()
return redirect('home')
context ={}
context.update(csrf(request))
context['request'] = request
context['form']= InputForm()
return render(request, "form.html", context)
HTML
{% block content %}
<form target="upload_frame" action="" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{ form.as_p }}<br>
<input type="submit" name="submit" value="Upload" id="submit">
</form>
{% endblock %}
Given the above code I am not sure why I am unable to post values to DB.
My second question is that I want to create a derived field that sums ops1
and ops2
and I want it show to user. I tried adding another field using code below but I am getting error of unrecognized fields in save function.
class InputForm(forms.ModelForm):
class Meta:
model = ManHour
fields = ['station', 'ops_1', 'ops_2', 'ops_3']
def save(self, commit=True):
self.total_ops = self.ops_1 + self.ops_2
return super(InputForm, self).save()
I am getting an error instance of InputForm has no ops_1 member
.
So I've two two question
Update
Scripts after applying changes:
Model
from django.db import models
class ManHour(models.Model):
station_choices = (
('alpha','A'),
('beta', 'B'),
('gamma','G'),
)
station = models.CharField(
max_length=3,
choices=station_choices,
)
date = models.DateTimeField(auto_now=True)
ops_1 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
ops_2 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
ops_3 = models.DecimalField(max_digits= 5, decimal_places= 3, default = 1)
Form
from django import forms
from webapp.models import ManHour
class InputForm(forms.ModelForm):
class Meta:
model = ManHour
fields = ['station', 'ops_1', 'ops_2', 'ops_3']
Admin
from django.contrib import admin
from .models import ManHour
# Register your models here.
admin.site.register(ManHour)
Views
from django.shortcuts import render, redirect
from django.template.context_processors import csrf
from django.http import HttpResponse
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout, authenticate
from django.contrib import messages
from .form import InputForm
from django.urls import reverse
from django.contrib.auth.decorators import login_required
# Create your views here.
def home_view(request, **kwargs):
return render(request, 'home.html', {})
def login_request(request):
if request.method == 'POST':
form = AuthenticationForm(request=request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
messages.info(request, f"You are now logged in as {username}")
return redirect('form')
else:
messages.error(request, "Invalid username or password.")
else:
messages.error(request, "Invalid username or password.")
form = AuthenticationForm()
return render(request = request,
template_name = "login.html",
context={"form":form})
@login_required(login_url='login')
def form_page(request):
if request.method == 'POST':
properties_Form = InputForm(request.POST)
if properties_Form.is_valid():
instance = properties_Form.save()
total_ops = instance.ops_1 + instance.ops_2
redirect("%s?total_ops=%s" % (reverse('home'), total_ops))
context = {}
context['request'] = request
context['form']= InputForm()
return render(request, "form.html", context)
base.HTML
<!DOCTYPE html>
<html>
<head>
<title>Budget Data</title>
<meta charset="utf-8" />
{% load staticfiles %}
<link rel='stylesheet' href="{% static 'css/bootstrap.min.css'%}", type="text/css" />
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
login.HTML
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endblock %}
form.html
{% extends 'base.html' %}
{% block title %}Form{% endblock %}
{% block content %}
<form target="upload_frame" action="" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{ form.as_p }}<br>
<input type="submit" name="submit" value="Upload" id="submit">
</form>
{% endblock %}
URLS.py
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import path
from pages import views
urlpatterns = [
path('home/', views.home_view, name='home'),
path('admin/', admin.site.urls),
path('login/', views.login_request, name='login'),
path('form/', views.form_page, name='form'),
I've updated the question to make changes as per the answer, however I am unable to view the evaluated field and I am unable to POST data to db.
Upvotes: 1
Views: 81
Reputation: 5874
If you want to get only data of form then you can access its through cleaned_data
(Django Docs).
class InputForm(forms.ModelForm):
class Meta:
model = ManHour
fields = ['station', 'ops_1', 'ops_2', 'ops_3']
def save(self, commit=True):
self.total_ops = self.cleaned_data.get("ops_1", 0) + self.cleaned_data.get("ops_2", 0)
return super(InputForm, self).save(commit=commit)
If you wand to modify instance first of all you need to call super(InputForm, self).save(commit=False)
(Django Docs) method to get instance.
Also your form can't be valid. Because station
field has max_length=3
. And some choices are length 4 and 5.
It must be:
station = models.CharField(
max_length=5,
choices=station_choices,
)
Update
If you want to do some calculation with the form data and provide it to the home
view you can use GET parameters for that, like the following:
from django.urls import reverse
def form_page(request):
context = {}
try:
man_hour = ManHour.objects.get(pk=request.GET.get("pk"))
except ManHour.DoesNotExist:
man_hour = None
if man_hour:
context["total_ops"] = man_hour.ops_1 + man_hour.ops_2
if request.method == 'POST':
properties_Form = InputForm(request.POST, instance=man_hour)
if properties_Form.is_valid():
obj = properties_Form.save()
return redirect("%s?pk=%s" % (reverse('form'), obj.pk))
else:
context['form']= InputForm(instance=man_hour)
return render(request, "form.html", context)
In HTML add url action
to the form tag to prevent opening in new tab and for calculation you can use jQuery
:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" async></script>
</head>
<body>
<p>This page is loaded with jquery.</p>
<form target="upload_frame" action="." method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{ form.as_p }}<br>
<input type="text" name="total_ops" value="{{ total_ops }}" disabled><br>
<input type="submit" name="submit" value="Upload" id="submit">
</form>
<script>
$(document).ready(function() {
$('input[name="ops_1"],input[name="ops_2"],input[name="ops_3"]').change(function() {
let ops_1 = parseFloat($('input[name="ops_1"]').val());
let ops_2 = parseFloat($('input[name="ops_2"]').val());
let ops_3 = parseFloat($('input[name="ops_3"]').val());
$('input[name="total_ops"]').val(ops_1 + ops_2 + ops_3);
})
});
</script>
</body>
</html>
Actually you don't need to override the save()
method of ModelForm
.
Upvotes: 2