Attempting to set related model fields via parent function call(s) - python

I am writing a Compact Disk Library editing routine. The application allows you to enter a CD Artist Name, and CD Title and the total time of the CD. User can then enter track information. While entering track information I want the application to display Current run time including this track, and time remaining based on length of the CD. The models and functions are below
class Cd(models.Model):
artist_name = models.CharField(max_length=155)
cd_title = models.CharField(max_length=155)
cd_total_time = models.TimeField(default="00:00:00")
cd_total_time_delta = models.DurationField(default=timedelta)
cd_run_time = models.TimeField(default="00:00:00",blank=True)
cd_run_time_delta = models.DurationField(default=timedelta)
cd_remaining_time = models.TimeField(default="00:00:00",blank=True)
cd_remaining_time_delta = models.DurationField(default=timedelta)
def convert_to_delta(self,time_in):
hold_time = time_in.strftime("%H:%M:%S")
t = datetime.strptime(hold_time,"%H:%M:%S")
return(timedelta(hours=t.hour, minutes=t.minute, seconds=t.second))
def calculate_time(self):
cd_total_time_delta = self.convert_to_delta(self.cd_total_time)
cd_total_run_time_delta = timedelta(minutes=0)
for track in self.cd_tracks.all():
cd_total_run_time_delta += track.trk_length_time_delta
track.trk_run_time_delta += cd_total_run_time_delta
track.trk_run_time = f"{track.trk_run_time_delta}"
track.trk_remaining_time_delta = cd_total_time_delta - cd_total_run_time_delta
track.trk_remaining_time = f"{track.trk_remaining_time_delta}"
self.cd_run_time_delta = cd_total_run_time_delta
self.cd_run_time = f"{self.cd_run_time_delta}"
self.cd_remaining_time_delta = self.cd_total_time_delta - cd_total_run_time_delta
self.cd_remaining_time = f"{abs(self.cd_remaining_time_delta)}"
def save(self, *args, **kwargs):
self.calculate_time()
super().save(*args,**kwargs)
def __str__(self):
return f"{self.artist_name} : {self.cd_title}"
class Track(models.Model):
cd_id = models.ForeignKey(Cd, on_delete=models.CASCADE,
related_name='cd_tracks',
)
track_title = models.CharField(max_length=50)
track_number = models.IntegerField()
trk_length_time = models.TimeField(null=True,default=None, blank=True)
trk_length_time_delta = models.DurationField(default=timedelta)
trk_run_time = models.TimeField(default="00:00:00",blank=True)
trk_run_time_delta = models.DurationField(default=timedelta)
trk_remaining_time = models.TimeField(default="00:00:00",blank=True)
trk_remaining_time_delta = models.DurationField(default=timedelta)
def calculate_track_delta(self):
self.trk_length_time_delta = self.cd_id.convert_to_delta(self.trk_length_time)
def save(self, *args, **kwargs):
self.calculate_track_delta()
super().save(*args,**kwargs)
self.cd_id.save()
def __str__(self):
return f"{self.track_title}"
When I attempt to update a track by entering in the track length time, name etc. and pressing submit, it should calculate all of the track data for each track. It DOES calculate the CD Total run time and remaining time, but the track values do not get updated. I am thinking my code isn't actually referencing the actual object correctly? Or the parent is not saving the child data...(how would I write that?).
Thanks
This is what the actual Parent Update Form looks like:
The Run Time I entered manually via admin, to see if that helped (it didn't). The time remaining should be the total time minus run time (run time increases of course for each track).
below is the template itself:
{% extends 'base.html' %}
{% load static %}
{% block title %} Update CD {% endblock title %}
{% block content %}
<h1>CD Update </h1>
{% if submitted %}
<p>
Your CD information was submitted successfully. Thank You.
</p>
{% else %}
<form action="" method="post" novalidate>
<table>
{{ form.as_table }}
{% if not cd.cd_tracks.all %}
No Tracks Added
{% else %}
<TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%">
<TR BGCOLOR="#B0B0FF">
<TD></TD>
<TD ALIGN="Center"> Track #</TD>
<TD ALIGN="Center"> Cut Title</TD>
<TD ALIGN="Center">Track Length</TD>
<TD ALIGN="Center" BGCOLOR="#CC99CC">Run Time</TD>
<TD ALIGN="Center" BGCOLOR="#CC99CC">Time Remaining</TD>
</TR>
{% for tracks in cd.cd_tracks.all %}
<TR>
<TD ALIGN="Center" rowspan="1" height="33" width="33">
<!-- Turning Off anchor No mix view yet
<A href=" url 'cd_mixed_view' cd.pk tracks.pk ">
-->
<IMG SRC="{% static 'images/edit.gif' %}">
</A>
</TD>
<TD ALIGN="Left" VALIGN="Top" WIDTH="10"> {{ tracks.track_number }}</TD>
<TD ALIGN="Left" VALIGN="Top"> {{ tracks.track_title }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ tracks.trk_length_time|time:"H:i:s" }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ tracks.trk_run_time|time:"H:i:s" }}</TD>
{% if tracks.trk_remaining_time_delta < "00:00:00" %}
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> (-{{ tracks.trk_remaining_time|time:"H:i:s" }})</TD>
{% else %}
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> {{ tracks.trk_remaining_time|time:"H:i:s" }}</TD>
{% endif %}
</TR>
{% endfor %}
</TABLE>
{% endif %}
<tr>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
{% csrf_token %}
</form>
{% endif %}
{% endblock content %}

The code was close. The most major problem was I was not saving the child model in the parent correctly (or at all really).
Uddate model is :
class Cd(models.Model):
artist_name = models.CharField(max_length=155)
cd_title = models.CharField(max_length=155)
cd_total_time = models.TimeField(default="00:00:00")
cd_total_time_delta = models.DurationField(default=timedelta)
cd_run_time = models.TimeField(default="00:00:00",blank=True)
cd_run_time_delta = models.DurationField(default=timedelta)
cd_remaining_time = models.TimeField(default="00:00:00",blank=True)
cd_remaining_time_delta = models.DurationField(default=timedelta)
def convert_to_delta(self,time_in):
hold_time = time_in.strftime("%H:%M:%S")
t = datetime.strptime(hold_time,"%H:%M:%S")
return(timedelta(hours=t.hour, minutes=t.minute, seconds=t.second))
def calculate_time(self):
cd_total_time_delta = self.convert_to_delta(self.cd_total_time)
cd_total_run_time_delta = timedelta(minutes=0)
for track in self.cd_tracks.all():
cd_total_run_time_delta += track.trk_length_time_delta
track.trk_run_time_delta = cd_total_run_time_delta
track.trk_run_time = f"{track.trk_run_time_delta}"
track.trk_remaining_time_delta = cd_total_time_delta - cd_total_run_time_delta
track.trk_remaining_time = f"{abs(track.trk_remaining_time_delta)}"
super(Track,track).save()
self.cd_run_time_delta = cd_total_run_time_delta
self.cd_run_time = f"{self.cd_run_time_delta}"
self.cd_remaining_time_delta = self.cd_total_time_delta - cd_total_run_time_delta
self.cd_remaining_time = f"{abs(self.cd_remaining_time_delta)}"
def save(self, *args, **kwargs):
self.calculate_time()
super().save(*args,**kwargs)

Related

Display data in a table only of the user logged in

Hello I want to display data of the user that is logged in form models into a table written in html
My views.py { I am displaying data from two different models in one table }
def managestugriev(request):
from_stugrievance = studentgriev.objects.all()
from_facgriev = facgrieve.objects.all()
return render(request,'manageGriev.html',
{"data_form_stu":from_stugrievance,"data_from_fac":from_facgriev})
template.html
<div>
<div>
<h2><center>Manage Your Grievances Here </h2>
<h3>Your Total Grievances: {{data|length}}</h3>
<h3></h3>
<table class="center">
<thead>
<tr text-align="justify">
<th>ID</th>
<th>Grievance</th>
<th>Date & Time</th>
<th>Status</th>
<th>Solution</th>
</tr>
</thead>
<tbody>
{% for i in data_form_stu %}
<tr text-align="justify">
<td padding:10px>{{forloop.counter}}</td>
<td>{{i.grievance}}</td>
<td>{{i.date_time}}</td>
<td>{{i.status}}</td>
{% for i in data_from_fac%}
<td>{{i.solution}}</td>
{% endfor %}
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
models.py {Two models from which I am displaying the data}
class studentgriev(models.Model):
ch = (
("Solved","Solved"),("Pending","Pending"),("Not Solved","Not Solved")
)
name = models.CharField(max_length=30,default='',null=False)
contactnum = models.IntegerField(default='',null=False)
email = models.EmailField(max_length=50,default='',null=False)
grievance = models.TextField(default='',null=False)
date_time = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=100,choices=ch,default='')
def __str__(self):
return self.name + " "
class facgrieve(models.Model):
solution = models.TextField(default='',null=False)
def __str__(self):
return self.solution + " "
Please can anyone help !

Django cumulative value displayed in template

I’m new to Django and Python and have been plugging through Python Crash Course. I have finished that and now have been making my own Django project, adding some extra bits in.
Currently, I have a table of entries from my model which I am displaying with a template, each entry in the table has a time and some other data. What I would like is the value for the cumulative time in a column, next to each entries time ie
Lesson
Lesson time
cumulative time
Lesson1
0.5
0.5
Lesson2
1
1.5
Lesson3
1.3
2.8
I’m just really stuck on how to get this done, I have looked at lot’s of stack overflow and tried various ways that I just can’t get to work correctly. Looking at other examples they use annotate() and cumsum, but I’ve not been able to get that to work. I’ve done count and sum of other values but this has got me stuck. I think I need to loop over it in my view, but not sure how to associate each value to a cumulative time.
Any help would be greatly received.
Also, sorry this isn't very well written or succinct, programming doesn't come naturally to me.
My topics.py
def topics(request):
"""Show all the topics"""
# Get the public topics
public_topics = Lessontopic.objects.filter(public=True).order_by('date_added')
# Get the private topics
if request.user.is_authenticated:
private_topics = Lessontopic.objects.filter(owner=request.user).order_by('date_added')
topics = private_topics
"""By Adding private into topics, seeing all public topics not just users
this way any topic added by authenticated user comes up in private, even if
it is also visible in public"""
time = Lessontopic.objects.aggregate(Sum('lesson_time'))
total_time = time.get('lesson_time__sum')
total_time = float(total_time)
lessons = Lessontopic.objects.all().count()
print(f"There has been {lessons} lessons ")
solo = (Lessontopic.objects.filter(solo_lesson=True)
.aggregate(Sum('lesson_time')))
solo_time = solo.get('lesson_time__sum')
print(f"solo lesson flying time {solo_time} hours")
solo_num = Lessontopic.objects.filter(solo_lesson=True).all().count()
dual = (Lessontopic.objects.filter(solo_lesson=False)
.aggregate(Sum('lesson_time')))
dual_time = dual.get('lesson_time__sum')
remaining_time = 50 - total_time
#Make a pie chart.
labels = ['Solo', 'Dual']
values = [solo_time, dual_time]
chat = ['this is long']
# Visualise the results
data=[Pie(labels=labels,text=chat,values=values,pull=[0.1, 0],
textposition='outside')
]
x_axis_config = {'title': 'Hours'}
y_axis_config = {'title': 'Lesson type'}
my_layout = Layout(title='Flying time Solo vs Dual Instruction',title_font_color='black' ,
title_font_size=30, title_x=0.5, legend_bordercolor='green', legend_borderwidth=5 )
fig = ({'data': data, 'layout': my_layout})
div = offline.plot(fig, auto_open=False, output_type='div')
cumulative_time = Lessontopic.objects.annotate(
cumulative_times=Window(
expression = Sum('lesson_time'),
order_by=F('date_added').asc(),
frame=RowRange(start=None, end=0)
)
)
context = {'topics': topics, 'cumulative_time':cumulative_time,'lessons':lessons, 'solo_time':solo_time,
'solo_num':solo_num, 'dual_time':dual_time,'solo_num':solo_num,
'remaining_time':remaining_time, 'dual':dual,'graph':div,}
else:
topics = public_topics
context = {'topics': topics}
return render(request, 'flying_logs/topics.html', context)
my model.py
from django.db import models
from django.contrib.auth.models import User
from django.forms.widgets import DateInput
from django import forms
import json
import requests
# Create your models here.
class Lessontopic(models.Model):
"""The topic of each lesson or day flying"""
text= models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False, verbose_name="Make post public?",
help_text="click on this form if you want it to be viewed by anyone")
lesson_number = models.PositiveIntegerField(blank=True, null=True)
lesson_time = models.DecimalField('enter flight time', max_digits=2, decimal_places=1)
solo_lesson = models.BooleanField(default=False, verbose_name="Were you solo for the lesson",
help_text="Click if were flying solo for the lesson")
runway_direction = models.PositiveIntegerField(
verbose_name="Select runway direction: 07 or 25")
number_landings = models.PositiveIntegerField(blank=True, default=1,
help_text="Enter how many landings")
date = models.DateTimeField()
time_of_lesson = models.PositiveIntegerField(
verbose_name="time that the lesson started")
weather_data = models.CharField(max_length=200)
adding = models.TextField(default=None, null=True, blank=True)
def __str__(self):
"""Return a string representation of the modeel"""
return self.text
My template topics.html
{% extends "flying_logs/base.html" %}
<h1>Topics</h1>
{% block page_header %}
{% endblock page_header %}
{% block content %}
<div class="container">
<table class="table text-center table-hover table-bordered" >
<tr><tr class="table-primary">
<th style="width: 10%">Lesson No.</th>
<th scope="col">Date</th>
<th scope="col">Lesson</th>
<th scope="col">Dual/Solo
<th scope="col">Flying time</th>
<th scope="col">Cumulative</th>
</tr>
</thead>
{% for topic in topics %}
{% if topic.solo_lesson %}
<tr class="table-success">
{% endif %}
<td class="text-center"> {{topic.lesson_number}}</td>
<td>{{ topic.date|date:'d/m/Y'}}</td>
<td>{{ topic }}</td>
<td>{{ topic.solo_lesson|yesno:"Solo, Dual" }}</td>
<td class="text-center">{{topic.lesson_time}}</td>
<td>Time so far{{ cumulative_time}}</td>
</tr>
{% endfor %}</table>
</div>
<div class="container">
<table class="table text-center table-hover table-bordered" >
<thread>
<tr><tr class="table-primary">
<th style="width: 5%">Solo</th>
<th style="width: 20%">Dual</th>
<th style="width: 20%">total time</th>
<th style="width: 20%">Time remaing</th>
<th style="width: 20%"> Solo Lessons</th>
<th style="width: 35%">Number of lessons</th>
</tr>
</thead>
<td>{{solo_time|floatformat:1}}</td>
<td>{{dual_time|floatformat:1}}</td>
<td>{{total_time}}</td>
{% if remaining_time >= 0 %}
<td class="table-danger">{{ remaining_time|floatformat:1 }}</td>
{% elif remaining_time <= 0 %}
<td class="table-success">You've done the minimum hours!!</td>
{% endif %}
<td class="text-center"> {{ solo_num}} </td>
<td>{{lessons}}</td>
</tr>
</tr>
</table>
</div>
<h3><a href="{% url 'flying_logs:new_topic' %}"><button name="new entry"
class="btn btn-primary">Add a new topic</button></a></h3>
{% if graph %}
<div style="width:600;height:500">
{{ graph|safe }}
</div>
{% endif %}
{% endblock content %}

Trying to set non-model field in model form to some other field that exists in the model

I have a form that I need to add an extra field to - and it needs to have an initial value of the data model's time field (called seg_length_time).
I didn't expect the code to work because I know I need to convert the time into a string from the model, but I can't seem to figure out how to set the field to begin with. The current code returns an error 'SegmentForm' object has no attribute 'pk'. I have tried id , and a couple of other things but haven't correctly referenced the specific object. For instance - I tried Segemt.object.values('seg_length_time') but then I get all of the seg_length_time key pairs.
See forms.py code below:
import re
from datetime import datetime,timedelta
class SegmentForm(forms.ModelForm):
str_seg_length_time = forms.CharField(max_length=8)
class Meta:
model = Segment
exclude = ('seg_length_time_delta',
#'seg_length_time',
'seg_run_time',
'seg_run_time_delta' ,
'seg_remaining_time',
'seg_remaining_time_delta',
'program_id',
'audit_user',
)
def __init__(self, *args, **kwargs):
obj = Segment.objects.get(id=self.instance.pk)
self.fields['str_seg_length_time'] = obj.seg_length_time
super().__init__(*args, **kwargs)
def clean_str_seg_length_time(self):
str_seg_time = self.cleaned_data['str_seg_length_time']
if (re.search("[^\d:]", str_seg_time) ): # check that only digits and : are in our time string
raise ValidationError("Segment Time: There are illegal characters in segment time. Valid format:[HH:MM:SS].")
if (re.search(".*:.*:.*:.*", str_seg_time) ): # check for more than two : signs
raise ValidationError("Segment Time: There are too many colons. Valid format:[HH:MM:SS].")
if ( re.search("^\d+$", str_seg_time) ): # time defaults to minutes if not specified
str_seg_time = "00:" + str_seg_time + ":00"
if ( re.search("^\d*:\d*$", str_seg_time) ): # time defaults to minutes/seconds if not specified
str_seg_time = "00:" + str_seg_time
try:
t = datetime.strptime(str_seg_time,"%H:%M:%S")
except:
raise ValidationError('Segment Time : Could not convert time to HH:MM:SS - Invalid Time')
self.seg_length_time = t
return str_seg_time
def form_valid(self, form):
form.instance.audit_user = self.request.user
return super().form_valid(form)
The model.py is below:
from django.db import models
from django.urls import reverse
from datetime import datetime, timedelta
class Program(models.Model):
air_date = models.DateField(default="0000-00-00")
air_time = models.TimeField(default="00:00:00")
service = models.CharField(max_length=10)
block_time = models.TimeField(default="00:00:00")
block_time_delta = models.DurationField(default=timedelta)
running_time = models.TimeField(default="00:00:00",blank=True)
running_time_delta = models.DurationField(default=timedelta)
remaining_time = models.TimeField(default="00:00:00",blank=True)
remaining_time_delta = models.DurationField(default=timedelta)
title = models.CharField(max_length=190)
locked_flag = models.BooleanField(default=False)
deleted_flag = models.BooleanField(default=False)
library = models.CharField(null=True,max_length=190,blank=True)
mc = models.CharField(null=True,max_length=64)
producer = models.CharField(null=True,max_length=64)
editor = models.CharField(null=True,max_length=64)
remarks = models.TextField(null=True,blank=True)
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
def convert_to_delta(self,time_in):
#print("Lengthof time_in = %s" % len(time_in))
hold_time = time_in.strftime("%H:%M:%S")
t = datetime.strptime(hold_time,"%H:%M:%S")
return(timedelta(hours=t.hour, minutes=t.minute, seconds=t.second))
def calculate_time(self):
block_time_delta = self.convert_to_delta(self.block_time)
total_run_time_delta = timedelta(minutes=0)
for segs in self.segments.all():
total_run_time_delta += segs.seg_length_time_delta
segs.seg_run_time_delta = total_run_time_delta
segs.seg_run_time = f"{segs.seg_run_time_delta}"
segs.seg_remaining_time_delta = block_time_delta - total_run_time_delta
segs.seg_remaining_time = f"{abs(segs.seg_remaining_time_delta)}"
super(Segment,segs).save()
self.running_time_delta = total_run_time_delta
self.running_time = f"{self.running_time_delta}"
self.remaining_time_delta = self.block_time_delta - total_run_time_delta
self.remaining_time = f"{abs(self.remaining_time_delta)}"
def calculate_sequence(self):
for index,segs in enumerate(self.segments.all(),1):
segs.sequence_number = index
super(Segment,segs).save()
def save(self, *args, **kwargs):
self.calculate_sequence()
self.calculate_time()
super().save(*args,**kwargs)
def __str__(self):
return f"{self.pk} : {self.title}"
def get_absolute_url(self):
#return reverse('program_detail', args=[str(self.id)])
return reverse('program-detail', kwargs={'pk': self.pk})
class Segment(models.Model):
class Meta:
ordering = ['sequence_number']
program_id = models.ForeignKey(Program,
on_delete=models.CASCADE,
related_name='segments', # link to Program
)
sequence_number = models.DecimalField(decimal_places=2,max_digits=6,default="0.00")
title = models.CharField(max_length=190)
bridge_flag = models.BooleanField(default=False)
seg_length_time = models.TimeField(null=True,default=None, blank=True)
seg_length_time_delta = models.DurationField(default=timedelta)
seg_run_time = models.TimeField(default="00:00:00",blank=True)
seg_run_time_delta = models.DurationField(default=timedelta)
seg_remaining_time = models.TimeField(default="00:00:00",blank=True)
seg_remaining_time_delta = models.DurationField(default=timedelta)
author = models.CharField(max_length=64,null=True,default=None,blank=True)
voice = models.CharField(max_length=64,null=True,default=None,blank=True)
library = models.CharField(max_length=190,null=True,default=None,blank=True)
summary = models.TextField()
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
def save(self, *args, **kwargs):
self.seg_length_time_delta =
self.program_id.convert_to_delta(self.seg_length_time)
super().save(*args,**kwargs)
self.program_id.save()
def get_absolute_url(self):
return reverse('program_detail', kwargs={'pk': self.program_id.pk} )
def save( self, *args, **kwargs):
super().save(*args,**kwargs)
self.program_id.save()
def __str__(self):
return f"{self.title}"
The View is the following:
class ProgramMixView(LoginRequiredMixin,UpdateView):
model = Segment
template_name = 'program_mix_view.html'
form_class = SegmentForm
context_object_name = 'program_edit'
def get_context_data(self, **kwargs):
context = super(ProgramMixView,self).get_context_data(**kwargs)
cur_segment = Segment.objects.get(id=self.kwargs['pk'])
context['program_info'] = Program.objects.get(id=cur_segment.program_id.pk)
return context
class SegmentCreateView(LoginRequiredMixin,CreateView):
model = Program
template_name = 'segment_create_view.html'
form_class = SegmentForm
context_object_name = 'program_seg_create'
And the actual template program_mix_template.html
{% if program_info %}
<TABLE ID="pro-table" WIDTH="100%">
<!-- <TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%"> -->
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Program Title:</TD><TD ALIGN="Left">{{ program_info.title|truncatechars:30 }}</TD>
<TD ALIGN="Right">Library:</TD><TD ALIGN="Left"> {{ program_info.library }}</TD>
<TD ALIGN="Right">Service Bureau:</TD><TD ALIGN="Left"> {{ program_info.service }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Program Id:</TD><TD ALIGN="Left"> {{ program_info.pk }}</TD>
<TD ALIGN="Right">Air Date:</TD><TD ALIGN="Left"> {{ program_info.air_date }}</TD>
<TD ALIGN="Right">Air Time</TD><TD ALIGN="Left"> {{ program_info.air_time|time:"H:i:s" }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Producer:</TD><TD ALIGN="Left"> {{ program_info.producer }}</TD>
<TD ALIGN="Right">Editor:</TD><TD ALIGN="Left"> {{ program_info.editor }}</TD>
<TD ALIGN="Right">MC:</TD><TD ALIGN="Left"> {{ program_info.mc }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD BGCOLOR="#99CCFF" ALIGN="Right">Duration:</TD>
<TD BGCOLOR="#99CCFF" ALIGN="Left"> {{ program_info.block_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Right">Rem. Time:</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> {{ program_info.remaining_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Right">Run Time:</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Left"> {{ program_info.running_time|time:"H:i:s" }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Remarks:</TD><TD ALIGN="Left" COLSPAN="5"><PRE>{{ program_info.remarks|truncatechars:180 }}</TD>
</PRE></TD>
</TR>
</TABLE>
{% if program_info.segments.all %}
<TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%">
<TR BGCOLOR="#B0B0FF">
<TD ALIGN="Center"> #</TD>
<TD ALIGN="Center">Segment Title</TD>
<TD ALIGN="Center">Summary</TD>
<TD ALIGN="Center">Library</TD>
<TD ALIGN="Center">Author</TD>
<TD ALIGN="Center">Voice</TD>
<TD ALIGN="Center">Segment time</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Center">Run time</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Center">Rem. time</TD>
</TR>
{% for segments in program_info.segments.all %}
{% if program_edit.pk == segments.id %}
<form method="post" action="">
{% csrf_token %}
<TR BGCOLOR="#B0B0FF">
<TD ALIGN="Left" VALIGN="Top" WIDTH="35">{{ form.sequence_number }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.title }}</TD>
<TD ALIGN="Left" VALIGN="Top"><PRE>{{ form.summary }}</PRE></TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.library }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.author }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.voice }}</TD>
<TD ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ form.str_seg_length_time }}</TD>
</TR>
<TR>
<td><input type="submit" Value="Update"></td>
</tr>
</form>
{% if form.errors %}
<!-- Error messaging -->
<div id="errors">
<div class="inner">
<p>There were some errors in the information you entered. Please correct the following:</p>
<ul>
{% for field in form %}
{% if field.errors %}
<li> {{ field.errors|striptags }}</li><br>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% else %}
<tr BGCOLOR="#B0B0FF">
<TD ALIGN="Left" VALIGN="Top" WIDTH="35">{{ segments.sequence_number }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.title }}</TD>
<TD ALIGN="Left" VALIGN="Top"><PRE>{{ segments.summary|truncatechars:40 }}</PRE></TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.library }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.author }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.voice }}</TD>
<TD ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_length_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#CC99CC" ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_run_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_remaining_time|time:"H:i:s" }}</TD>
</TR>
{% endif %}
{% endfor %}
</TABLE>
{% else %}
No Segments
{% endif %}
{% endif %}
The field (str_seg_length_time)shows up on the form as nothing (Blanks), if I don't do some sort of initial code to set it from the model. Can I get the object by id, or dont I already have the object in the form at initialization time? I assume I will need to do some sort of strfdatetime() call to turn it into a string, but I don't know how to get the seg_length_time from the model to begin with...
Thanks.
(P.S. I don't just put the field from the model in the form because I am trying to change the way the default time entered is handled (HH:MM is the default - I need mm:ss or Minutes by default) i.e. 05:00 should be 5 minutes, NOT 5 hours)...
Your forms __init__ method is written as:
def __init__(self, *args, **kwargs):
obj = Segment.objects.get(id=self.instance.pk)
self.fields['str_seg_length_time'] = obj.seg_length_time
super().__init__(*args, **kwargs)
Let's note the problems here. Firstly obj = Segment.objects.get(id=self.instance.pk), I can see that you use this same form in a CreateView, obviously when an instance is not yet created it will not have a primary key, giving you an error. Secondly self.fields['str_seg_length_time'] this will give you an error because you are calling this before even calling super().__init__ which is what initializes self.fields. Thirdly = obj.seg_length_time what even are you trying to do here? Do you want to set the initial value of the field? Because currently you replace the field you declare with this value instead.
What is the solution? It appears you just want to provide an initial value for the field, you don't need to override __init__ for this simple purpose. Going even further you just want the input in a custom format? No need to do all this for that, you can simply pass the input_formats [Django docs] kwarg for that to the field. The formats in this list will be tried in order and the first matching one will be used:
class SegmentForm(forms.ModelForm):
seg_length_time = forms.TimeField(input_formats=['%H:%M:%S', '%M:%S', '%M']) # Set custom formats here
class Meta:
model = Segment
exclude = ('seg_length_time_delta',
# 'seg_length_time',
'seg_run_time',
'seg_run_time_delta' ,
'seg_remaining_time',
'seg_remaining_time_delta',
'program_id',
'audit_user',
)
What if you want to use some custom formats for all time fields by default? Simply set the TIME_INPUT_FORMATS setting [Django docs] in settings.py:
TIME_INPUT_FORMATS = [
'%H:%M:%S',
'%M:%S',
'%M'
]
In your initialization of the SegmentForm the keyword self will refer to the SegmentForm class, not the model instance. That's why you get the error that the form does not have pk. To refer to the model instance use self.instance, which will refer to the instance of the underlying model.
def __init__(self, *args, **kwargs):
obj = Segment.objects.get(id=self.instance.pk)
self.fields['str_seg_length_time'] = obj.seg_length_time
super().__init__(*args, **kwargs)

Trying to add a form to a DetailView

I am writing a Detail View - and the form that is displayed is the particular Track that the user is adding/updating to the CD Entry (It's a CD Library application). The trick is I want to see everything else about the CD on the page as well as the form for the particular track. Having trouble figuring out how to get the form to be just the trac I am adding/updating.
Basically you can enter a CD Title,Artist, and total time of the CD into the CD model. Then the Tracks are stored in the Track Model, with their Foreign Key being the CD they are on.
While looking at a Detail View of the CD, the user can add or update a Particular track via a button. I'm trying to get the update part working.
Model Looks like this:
from django.db import models
from datetime import datetime, timedelta
class Cd(models.Model):
artist_name = models.CharField(max_length=155)
cd_title = models.CharField(max_length=155)
cd_total_time = models.TimeField(default="00:00:00")
cd_total_time_delta = models.DurationField(default=timedelta)
cd_run_time = models.TimeField(default="00:00:00",blank=True)
cd_run_time_delta = models.DurationField(default=timedelta)
cd_remaining_time = models.TimeField(default="00:00:00",blank=True)
cd_remaining_time_delta = models.DurationField(default=timedelta)
def save(self, *args, **kwargs):
super().save(*args,**kwargs)
def __str__(self):
return f"{self.artist_name} : {self.cd_title}"
class Track(models.Model):
cd_id = models.ForeignKey(Cd, on_delete=models.CASCADE,
related_name='cd_tracks',
)
track_title = models.CharField(max_length=50)
track_number = models.IntegerField()
trk_length_time = models.TimeField(null=True,default=None, blank=True)
trk_length_time_delta = models.DurationField(default=timedelta)
trk_run_time = models.TimeField(default="00:00:00",blank=True)
trk_run_time_delta = models.DurationField(default=timedelta)
trk_remaining_time = models.TimeField(default="00:00:00",blank=True)
trk_remaining_time_delta = models.DurationField(default=timedelta)
def save(self, *args, **kwargs):
super().save(*args,**kwargs)
self.cd_id.save()
def __str__(self):
return f"{self.track_title}"
The views.py snippet:
class Track_update(UpdateView):
model = Track
template_name = 'track_update.html'
fields = [ 'cd_id', 'track_title',
'track_number', 'trk_length_time'
]
success_url = "/"
class Cd_DetailView(DetailView):
model = Cd
template_name = 'cd_detail.html'
fields = ['artist_name','cd_title','cd_total_time',
'cd_run_time','cd_remaining_time'
]
class Cd_MixedView(FormMixin, DetailView):
model = Cd
template_name = 'cd_mixed_view.html'
form_class = TrackForm
def get_success_url(self):
return reverse('cd_detail {id}')
def get_context_data(self, **kwargs):
context = super(Cd_MixedView,self).get_context_data(**kwargs)
context['form'] = TrackForm(initial={
'cd_id':self.object
})
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self,form):
form.save()
return super(Cd_MixedView, self).form_valid(form)
The urls.py looks like
from django.urls import path
from django.contrib import admin
from .views import (
HomePageView,
Cd_Create,
Cd_Update,
Cd_DetailView,
List_Cds,
Track_Create,
Cd_MixedView,
)
urlpatterns = [
path('', HomePageView.as_view(), name = 'home'),
path('admin/', admin.site.urls),
path('cd/add/', Cd_Create.as_view(), name='cd_new'),
path('cd/update/<int:pk>', Cd_Update.as_view(), name='cd_update'),
path('cd/detail/<int:pk>', Cd_DetailView.as_view(), name='cd_detail'),
path('track/add/', Track_Create.as_view(), name='track_new'),
path('track/add/<int:pk>', Cd_MixedView.as_view(), name='cd_mixed_view'),
path('list/', List_Cds.as_view(), name='list_cds'),
]
The template looks like this:
<!-- templates/cd_mixed_view.html -->
{% extends 'base.html' %}
{% load static %}
{% block title %} CD Details{% endblock title %}
{% block content %}
<h1>CD Update Track </h1>
<p>Artist Name: {{ cd.artist_name}}
<p>Cd Title: {{ cd.cd_title }}
<p>Cd Total Time: {{ cd.cd_total_time|time:"H:i:s" }}
<p>Cd Run Time: {{ cd.cd_run_time|time:"H:i:s" }}
<p>Cd Remaining Time:
{% if cd.cd_run_time_delta > cd.cd_total_time_delta %}
(-{{ cd.cd_remaining_time|time:"H:i:s" }})
{% else %}
{{ cd.cd_remaining_time|time:"H:i:s" }}
{% endif %}
<TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%">
<TR BGCOLOR="#B0B0FF">
<TD></TD>
<TD ALIGN="Center"> Track #</TD>
<TD ALIGN="Center"> Cut Title</TD>
<TD ALIGN="Center">Track Length</TD>
<TD ALIGN="Center" BGCOLOR="#CC99CC">Run Time</TD>
<TD ALIGN="Center" BGCOLOR="#CC99CC">Time Remaining</TD>
</TR>
{% for tracks in cd.cd_tracks.all %}
*** This is the part I am having trouble with ***
{% if tracks.id = track number that was clicked %}
{form_as_p}
{% else %}
<TR>
<TD ALIGN="Center" rowspan="1" height="33" width="33">
<TD ALIGN="Left" VALIGN="Top" WIDTH="10"> {{ tracks.track_number }}</TD>
<TD ALIGN="Left" VALIGN="Top"> {{ tracks.track_title }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ tracks.trk_length_time|time:"H:i:s" }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ tracks.trk_run_time|time:"H:i:s" }}</TD>
{% if tracks.trk_run_time_delta > cd.cd_total_time_delta %}
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> (-{{ tracks.trk_remaining_time|time:"H:i:s" }})</TD>
{% else %}
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> {{ tracks.trk_remaining_time|time:"H:i:s" }}</TD>
{% endif %}
</TR>
{% endfor %}
</TABLE>
</table>
{% endblock content %}
So, how do I pass the Track ID into the template, so that I can display the form for THAT track, otherwise
display the track information for all the other tracks.
Any information about how to approach this would be greatly appreciated.
Below is a picture of what the Detail Screen looks like before attempting to update the Track.
Thanks
Did you think about adding the tracking id as a slug, creating another function in views, to pass it? with an 'a' tag, and passing an href, with inside it the foreign key if the track referring to the CD. You could pass the values in the context of the view.

Django: Trying to click on a link and remove an assigned client

Good morning. I am having an issue trying to remove a client from an assigned bed. I created a one-item form called "RoomUpdate" that will allow a user to add a client to a bed that is empty via a dropdown through a ModelChoiceField.
When the bed is full, it does not allow the access to the drop down, instead, I have a link that states "remove client." What I want to happen is when I click that button, it assigns the default value of None to that bed in that room.
What's tricky, at least to my new-ish to Django mind, is how I do this through multiple tables. Having looked for multiple answers and tried different things, I know I've lost track of what I'm doing so I definitely could use some help.
models.py
class Room(models.Model):
room_id = models.AutoField(primary_key=True)
room_number = models.CharField(max_length=5)
shelter_id = models.ForeignKey(Shelter)
max_occupancy = models.CharField(max_length=3)
floor_location = models.CharField(max_length=3)
def __str__(self):
return self.room_number
class Bed(models.Model):
bed_id = models.AutoField(primary_key=True)
room_id = models.ForeignKey(Room, related_name='beds')
bed_size = models.ForeignKey(BedSize)
client_assigned = models.ForeignKey(Clients, null=True, blank=True, default=None)
forms.py
class RoomUpdate(forms.ModelForm):
client_assigned = forms.ModelChoiceField(queryset=Clients.objects.all(), required=False)
#def __init__(self, *args, **kwargs):
#super(RoomUpdate, self).__init__(*args, **kwargs)
#self.fields['client_assigned'].choices.insert(0, ('','---------' ) )
class Meta:
model = Room
fields = ( 'client_assigned', )
views.py
def room_update(request, pk, template_name='shelter/room_edit.html'):
rooms = get_object_or_404(Room, pk=pk)
form = RoomUpdate(request.POST or None, instance=rooms)
beds = Bed.objects.filter(room_id=pk)
if form.is_valid():
form.save()
return redirect('/shelter/')
return render(request, template_name, {'form': form, 'rooms': rooms, 'beds':beds,})
def remove_client(request, pk):
rooms = get_object_or_404(Room, pk=pk)
bed = Bed.objects.filter(room_id=pk)
form = RoomUpdate(request.POST)
template_fail = 'clients/invalid_permissions.html'
if request.method=='POST':
if form.is_valid():
bed.objects.update(client_assigned=None)
bed.save()
else:
return redirect(request, template_fail)
return render_to_response(request, {'rooms': rooms, 'bed': bed})
template
<form action="" method="POST">
{% csrf_token %}
<div class="room box-shadow">
<h4>Room {{ rooms.room_number }}</h4>
<table>
{% for i in rooms.beds.all %}
<tr>
<td>Bed ID: </td>
<td>{{i.bed_id }}</td>
</tr>
<tr>
<td>Bed Size: </td>
<td>{{i.bed_size }}</td>
</tr>
<tr>
<td valign="top">Client: </td>
<td>
{% if i.client_assigned %}
{{ i.client_assigned }}
<br \>
Remove Client
{% else %}
{{ form.client_assigned }}
{% endif %}
</td>
</tr>
<tr>
<td colspan="2">
<hr class="style-two" />
</td>
</tr>
{% endfor %}
<tr>
<td><input type="submit" value="Submit" /></td>
<td></td>
</tr>
</table>
</div>
</form>
I've been playing around with this a bit and making some sort of progress. If I change the url from the same as the edit, I get it to work in that it deletes from the table and redirects the user to a new page.
I would prefer it not redirect the user to a new page, but rather, update the page that's there.
Thoughts?
The new view looks like this:
def remove_client(request, pk, template_name='shelter/test.html'):
bed = Bed.objects.filter(bed_id=pk).update(client_assigned=None)
return render(request, template_name, { 'bed':bed })
Further diving into this, I found a solution I rather like and actually works in a way I wanted but couldn't figure out. Instead of focusing on the room, I realized that I needed to focus on the smaller container -- the bed -- and since it can move around, it would be the better choice.
Currently, this functionality allows me to move beds to different rooms, remove clients by selecting the '----' selector, and allows me to add clients.
So here is the answer I came up with:
forms.py
class RoomUpdate(forms.ModelForm):
bed_id = forms.CharField()
room_id = forms.ModelChoiceField(queryset=Room.objects.all())
bed_size = forms.ModelChoiceField(queryset=BedSize.objects.all(), required=False)
client_assigned = forms.ModelChoiceField(queryset=Clients.objects.all(), required=False)
class Meta:
model = Bed
fields = ('bed_id', 'client_assigned', 'room_id', 'bed_size' )
views.py
def room_update(request, pk, template_name='shelter/room_edit.html'):
beds = get_object_or_404(Bed,pk=pk)
form = RoomUpdate(request.POST or None, instance=beds)
if form.is_valid():
form.save()
return redirect('/shelter/')
return render(request, template_name, {'form': form, 'beds':beds,})
room_edit.html
<form action="" method="POST">{% csrf_token %}
<div class="room box-shadow">
<h4>Room </h4>
<table>
<tr>
<td>Room: </td>
<td>{{ form.room_id }}</td>
</tr>
<tr>
<td>Bed ID: </td>
<td>{{ form.bed_id }}</td>
</tr>
<tr>
<td>Bed Size: </td>
<td>{{ form.bed_size }}</td>
</tr>
<tr>
<td valign="top">Client: </td>
<td>{{ form.client_assigned }}</td>
</tr>
<tr>
<td colspan="2"><hr class="style-two" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
<td></td>
</tr>
</table>
</div>
</form>

Categories

Resources