ToscaWidgets2 Capture Data from GrowingGridLayout - python

Currently working on a project with TurboGears2 and ToscaWidgets2. I have a form setup with a few static fields, name, date, and point of contact information. Inside this form I have added a sub form where the user can dynamically add numerous entries in a GrowingGridLayout. The form, its layout, and submitting information is all well and good but I'm having a hard time figuring out how to capture the information from the GrowingGridLayout once it's passed on for saving. Guess the main points are, how do I know how many entries were included in the form?
Included the code for the form:
class OnrampForm(twf.Form):
title = "Onramp Submission Form"
class child(twd.CustomisedTableForm):
onramp_name = twf.TextField(validator=twc.Required)
class Destinations (twd.GrowingGridLayout):
environment = twf.SingleSelectField(label='Environment', validator=twc.Validator(required=True), options=[<OPTIONS>])
location = twf.SingleSelectField(validator=twc.Required, label='Location', options=[<OPTIONS>])
jms_type = twf.SingleSelectField(label='JMS Type', validator=twc.Validator(required=True), options=[<OPTIONS>])
subscription_type = twf.SingleSelectField(label='Subscription Type', validator=twc.Validator(required=True), options=[<OPTIONS>])
onramp_status = twf.SingleSelectField(prompt_text='Status', options=['Initial Release', 'Update'], validator=twc.Required)
current_date = datetime.date.today()
need_by_date = twd.CalendarDatePicker(validators=[twc.Required, twc.DateTimeValidator])
need_by_date.default = current_date + datetime.timedelta(days=30)
organization = twf.TextField(validator=twc.Required)
poc_name = twf.TextField(validator=twc.Required)
poc_email = twf.EmailField(validator=twc.EmailValidator)
poc_phone = twf.TextField(validator=twc.Required)
poc_address = twf.TextField()
poc_city = twf.TextField()
poc_state = twf.TextField()
onramp_form = twf.FileField()
submit = twf.SubmitButton(value="Submit")
action = "/print_args"
submit = ""

If you controller #validates against the form you should get the data into the Destination parameter which should be a list of dictionaries.
Also I just noticed you have two nested forms, that's something that might confuse TW2 pretty much. What you wanted to do is probably have OnrampForm inherit CustomisedForm and then have child inherit TableLayout. See http://turbogears.readthedocs.org/en/latest/cookbook/TwForms.html#displaying-forms
PS: note that need_by_date.default = current_date + datetime.timedelta(days=30) will always return 30 days from when the server started as you are actually storing a current_date = datetime.date.today() class variable that gets computed when the module is imported and no more.
You should use default = Deferred(lambda: datetime.date.today() + datetime.timedelta(days=30)) to achieve that

Related

Verify a Django model field inside a Django model

I have a Django model called Attendance that has the clock in and clock in times of an employee along with the status of that entry, to see whether it's authorized or not. I then, am making another model called Payroll. I want this to check inside the Attendance entries to see all the Authorized entries and then do some action on them. How do I check all the status fields for all the entries in Attendance?
EDIT: Updated to better elaborate my question.
To better elaborate my question, this is how I've setup my Attendance model:
class CWorkAttendance(models.Model):
AUTO_ATT = "AU"
MANUAL_ATT = "MA"
WORK_ENTRY_TYPES = (
(AUTO_ATT, "Auto-Attendance"),
(MANUAL_ATT, "Manual-Attendance"),
)
AUTHORIZED = "AU"
UNAUTHORIZED = "UA"
WORK_ENTRY_STATUSES = (
(AUTHORIZED, "Athorized"),
(UNAUTHORIZED, "Un-Authorized"),
)
#Thank you motatoes
def face_locations_in(self, instance):
now = datetime.datetime.now()
return "attendance/{}/{}/in".format(instance.work_employee, now.strftime("%Y/%m/%d"))
def face_locations_out(self, instance):
now = datetime.datetime.now()
return "attendance/{}/{}/out".format(instance.work_employee, now.strftime("%Y/%m/%d"))
work_employee = models.ForeignKey('CEmployees', on_delete=models.CASCADE,)
work_start_time = models.DateTimeField()
work_end_time = models.DateTimeField(null=True)
work_duration = models.IntegerField(null=True)
work_entry_type = models.CharField(max_length=2,choices=WORK_ENTRY_TYPES)
work_entry_status = models.CharField(max_length=2, choices=WORK_ENTRY_STATUSES, default=WORK_ENTRY_STATUSES[1][0])
employee_face_captured_in = models.ImageField(upload_to=face_locations_in,)#////////
employee_face_captured_out = models.ImageField(upload_to=face_locations_out,)
If you look closely at the work_entry_status, it's a choice CharField that will contain the status of the entry (UNAUTHORIZED by default).
I want to create a Payroll model that will check for all the rows in the CWorkAttendance model and check their work_entry_status fields to see if they are Authorized, which is what I want to learn how to do.
If those fields are authorized, I want the grab the row's work_employee, work_duration and also some details from the original CEmployees row for the employee.
This is what I want my Payslip/Payroll model to look like:
class Payslip(models.Model):
GENERATED = "GEN"
CONFIRMED = "CON"
PAYSLIP_STATUS = (
(GENERATED, "Generated-UNSAVED"),
(CONFIRMED, "Confirmed-SAVED"),
)
payslip_number = models.IntegerField()#MM/YY/AUTO_GENERATED_NUMBER(AUTO_INCREMENT)
payslip_employee = models.ForeignKey('CEmployees', on_delete=models.CASCADE,)#Choose the employee from the master table CEmployees
payslip_generation_date = models.DateTimeField(default=datetime.datetime.now())#Date of the payroll generation
payslip_total_hours = models.IntegerField()#Total hours that the employee worked
payslip_from_date = models.DateField()"""The date from when the payslip will be made. The payslip will be manual for now, so generate it after choosing a a date to generate from."""
payslip_total_basic_seconds = models.IntegerField()#Total seconds the employee worked
payslip_total_ot_seconds = models.IntegerField()#Total overtime seconds the employee worked
payslip_basic_hourly_rate = models.IntegerField()#The basic hourly rate of the employee mentioned here. Take from the master employees table.
payslip_basic_ot_rate = models.IntegerField()#Taking the basic overtime rate from the master table
payslip_total_amount = models.FloatField()#The total amount of the payslip
payslip_entry_status = models.CharField(max_length=3, default=GENERATED)#The status of the pay slip.
Thanks,
Not sure if I understand your requirements well, so let me know if I misunderstood.
# `employee` is the work_employee in question
# if you don't want to filter by employee, remove `work_employee=employee`
attendances = CWorkAttendance.objects.filter(work_entry_status=CWorkAttendance.AUTHORIZED, work_employee=employee)
for attendances in attendances:
# do things with this attendance record
attendance.work_duration
attendance.employee
# ....
Update
Since you would like to do it manually, I would suggest having a separate view to generate the Payslip. The important thing is to know the date_from and the date_to for this payslip. I imagine that it is the managers who would have access to this view, so you would need the proper access controls set for it. I also think you need to have a payslip_to_date even if you are going to generate it until the current date, which will be useful for record keeping. I assume you have that column in the code below.
views.py:
from django.views import View
class GeneratePayslip(View):
"""
make sure you have the right access controls set to this view
"""
def post(self, request, **kwargs):
employee_id = kwags.POST.get("employee_id")
date_from = kwargs.POST.get("from_date")
date_to = kwargs.POST.get("to_date")
# we fetch all the objects within range
attendances = CWorkAttendance.objects.filter( \
work_entry_status=CWorkAttendance.AUTHORIZED, \
work_employee_id=employee_id, \
work_start_time__gte=date_from, \
work_end_time__lte=date_to \
)
hours = 0
for attendance in attendances:
# perform calculations to compute total sum and rate
pass
# create the payslip object here ..
# redirect to a success page and return
If you wanted to do it automatically later on, you may want to generate payslips automatically, once a month. For that you could use something like Celery to have periodic tasks that run in the background, for each employee. If this is the case you could move the above code to a file such as utils.py. you can create a method which takes employee_id, from_date, to_date, and then generate the payslip object, returning the payslip_id to the calling method

Django view objects filter with timezone.now().date or timezone.now().time-> expected string or bytes-like object

Hi i have some Django 11 project, my model look like
class Event(models.Model):
name = models.CharField(max_length=100, unique=True)
title = models.CharField(max_length=100)
info = models.CharField(max_length=100)
image = models.ImageField(upload_to='events/%Y/%m/%d')
start_date = models.DateField(default=timezone.now)
start_time = models.TimeField(default=timezone.now)
stop_date = models.DateField(default=timezone.now)
stop_time = models.TimeField(default=timezone.now)
place = models.ForeignKey('places.Place', on_delete=models.CASCADE)
company = models.ForeignKey('companies.Company', on_delete=models.CASCADE)
and my view look like
def place_website(request, place_id):
place_template = get_template('room.html')
place_obj = Place.objects.filter(id=place_id)
# filter for event obejts only for requested place, filtered for now and next events
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now(), stop_date__gte=timezone.now()).order_by('start_time')
place_context = {
'place_obj': place_obj,
'place_event_now': place_event_now,
'place_events_next': place_events_next,
}
return HttpResponse(place_template.render(place_context))
the thing i want to manage is to pass to template the list of filtered Event objects based on time.
Lets pick this line
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
it couse error "expected string or bytes-like object" but when i remove ".date" from "timezone.now()" error disappear (then filter do nothing) but i want to compare date to date and time to time.
How to do this properly ?
This approach to filter objects in view rather than in template is proper?
###### UPDATE ########
Its werid because after correction now i have no error but queryset is not filtered properly, look like only two first parameter is filtering ok and the another two is causing empty queryset.
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), start_time__lte=timezone.now().strftime('%H:%M:%S'), stop_time__gte=timezone.now().strftime('%H:%M:%S'))
I my database time is saved in format H:M:S and timezone.now().time() has different format so i modified filter with .strftime this didnt help, what i wont is to limit "place_event_now" queryset to particular object/objects that come true with condition start_time < currenttime < stop_time.
Another case is with place_event_next
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), stop_date__gte=timezone.now().strftime('%Y-%m-%d'), start_time__gt=timezone.now().strftime('%H:%M:%S')).order_by('start_time')
Event when i filter objects that start_time is greater than timezone.now() they still are in queryset.
Am I doing something wrong ?
I figured it out that timezone.now() return time not in my current timezone, i change it to timezone.localtime() and everything working perfect !!!
May be you need call date to date()
replace
filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
# ^^^ ^^^
to
filter(place=place_id, start_date=timezone.now().date(), stop_date__gte=timezone.now().date())
# ^^^ ^^^

Django forms DateTimeInput widget- how to specify max date?

I have a form displayed in my Django project, and one of the form fields is a DateTimeInput widget, defined with:
presentation_date = mDateTimeField(required=False, label="Presentation date", widget=forms.DateTimeInput(format='%d/%m/%Y %H:%M'))
This widget currently displays all dates between the start of last year to the end of this year (01/01/2016- 31/12/2017). However, at the end of last year this caused some issues, as it meant that users were unable to select dates for the beginning of this year. What I want to do is extend the range of the dates available for selection in the widget by one year (i.e the new range would be 01/01/2016- 31/12/2018).
I understand that it is possible to do this using form validation (for example, by writing a view such as clean_presentation_date() and performing the validation inside that view, but this won't solve the issue I'm having- as currently, dates before 01/01/2016 or after 31/12/2017 (displayed in the datetimepicker calendar that's shown when the user selects the field in the form) are 'greyed out' and it is not possible to select them. This is exactly the functionality that I want, but I just want to change the values of the dates on which it is performed, so that at least the whole of the next calendar year is always selectable.
I have searched for maxDate & minDate variables within the forms.py file where the form with this field is defined, but can't find anything that looks like it is what's restricting which dates are available to be selected, and which are not selectable.
The view that's showing the page with this form on it is defined with:
def concept(request, project_id):
project = Project.objects.prefetch_related('budget_versions').get(id=project_id)
deposit = Deposit.objects.get_or_create(project=project)[0]
presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn')
end_details = EndDetails.objects.get_or_create(project=project)[0]
presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations)
drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created'))
context = {
'project': project,
'presentations': presentations,
'presentation_formset': presentation_formset,
'drawing_formset': drawing_formset,
'deposit_form': DepositInfoForm(instance=deposit),
'ended_form': EndDetailsForm(instance=end_details),
'budget_notes_form': BudgetNotesForm(instance=project.budget_overview),
}
The particular form I'm looking at is the presentations one, defined in forms.py:
class FirstPresentationForm(ValidatedForm):
""" UNUSED """
who_presenting = forms.CharField()
details = forms.CharField(required=False, label='Original option costed')
presentation_date = mDateTimeField(required=False, label="Presentation date", widget=forms.DateTimeInput(format='%d/%m/%Y %H:%M')) #ERF(19/12/2016 # 1210) Remove 'datetimepicker' from field..., attrs=({'class':'datetimepicker'})))
class Meta:
model = Budget
fields = ('presentation_date','who_presenting','details')
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', {})
project = instance.project
who_presenting = [pe.employee.id for pe in project.assigned.select_related('employee').filter(role=Role.P)]
#Make into an array with two employee IDs, or None. If two results were found, they will already be in the right format
if len(who_presenting)==1:
who_presenting.append(None)
elif not who_presenting:
who_presenting = None
if instance.presentation_date:
pres_meeting, created = Meeting.objects.get_or_create(project=project, purpose='6')
self.pres_meeting_id = pres_meeting.id
self.pres_meeting_creator = pres_meeting.event_creator or ''
if created:
pres_meeting.date = instance.presentation_date
pres_meeting.save()
initial = kwargs.get('initial', {})
initial={
'who_presenting': who_presenting,
}
kwargs['initial'] = initial
super(FirstPresentationForm, self).__init__(*args, **kwargs)
self.fields['who_presenting'] = AutoFlexiSelect(model='e', required=False, choices=get_choices('DESIGN_EMPLOYEE_CHOICES'), current_id=who_presenting, label="Who is presenting")
self.fields['presentation_date'].widget.attrs.update({'data-meeting-id': getattr(self,'pres_meeting_id', ''), 'data-meeting-creator': getattr(self,'pres_meeting_creator', '')})
def save(self, commit=True):
project = self.instance.project
data = self.cleaned_data
try: ProjectEmployee.objects.filter(project=project, role=Role.P).delete() #Delete current records, if any, to prevent build up on editing this field
except ObjectDoesNotExist: pass
if data['who_presenting']:
designers = data['who_presenting']
# Get the ids from the form field (received as a string)
designers = [re.sub('\D+', '', s) for s in designers.split(',')]
who_presenting_1 = Employee.objects.get(id=designers[0])
who_presenting_2 = designers[1] #If only one employee in selected choice, this will be None
if who_presenting_2: who_presenting_2 = Employee.objects.get(id=designers[1]) #If two employees in selected choice, sets the second one
pe = ProjectEmployee(project=project, employee=who_presenting_1, role=Role.P)
pe.save()
if who_presenting_2: #If a second designer, delete as well
pe = ProjectEmployee(project=project, employee=who_presenting_2, role=Role.P)
pe.save()
if 'presentation_date' in self.changed_data:
from events.models import refresh_group_cache
print '************'
pres_meeting = Meeting.objects.get(project=project, purpose='6')
self.instance.meeting = pres_meeting
self.instance.save()
print 'Updating date', data['presentation_date'], pres_meeting.id
pres_meeting.date = data['presentation_date']
pres_meeting.save()
refresh_group_cache(pres_meeting.event_creator.calendar_id, pres_meeting.date.year, pres_meeting.date.month, pres_meeting.event_id, pres_meeting)
return super(FirstPresentationForm, self).save(commit=commit)
I have tried passing/ setting max_date as an attribute of the presentation_date variable, but it doesn't appear to have an attribute/ property by this name...
How can I specify a particular date as this widget's maxDate, so that the user is able to select dates up until December of next year, rather than just up until December of this year?
Edit
The mDateTimeField that's using the widget is also defined in forms.py, with:
class mDateTimeField(forms.DateTimeField):
def __init__(self, *args, **kwargs):
kwargs.setdefault('input_formats', DATE_INPUT_FORMATS)
super(mDateTimeField, self).__init__(*args, **kwargs)
This should help you:
widgets = {
'start_date': forms.DateInput(attrs={
'class':'datepicker', 'data-min': YOUR_MIN_DATE,
'data-max': YOUR_MAX_DATE}),
}
Usage:
minDate: $(this).data('min'),
maxDate: $(this).data('max'),

Django exclude on multiple fields in subquery

Given some code like this:
# coding: utf-8
import datetime
from django.db import models
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
class Premium(models.Model):
"""Access to Premium Features™®."""
end = models.DateField()
user = models.ForeignKey(User)
site = models.ForeignKey(Site)
def get_ending_premiums():
"""Get a queryset of all Premiums for which a user has none following."""
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
future_premiums = Premium.objects.filter(end__gt=tomorrow).values('user', 'site')
return Premium.objects.filter(end=tomorrow).exclude(
# Would love if something like this actually worked...
user_and_site__in=future_premiums,
)
How can I complete get_ending_premiums()? One of the key things is I want Premiums only when there isn't another one that ends later, but on a per-site basis. So if a user has another Premium on groceries.com, the one about to end tomorrow doesn't get returned, but if they don't have another Premium on officesupplies.com, that one does get returned.
(Note the line with with the comments before it doesn’t actually work... that’s the part I need to complete.)
I can work out how to do this outside the ORM but I’d really prefer an ORM solution, as we’re planning on switching database vendors in a few months, so I’m trying to avoid raw SQL as much as possible.
Here’s a test for the behavior I’d like to get:
class PremiumTest(TestCase):
def test_gets_ending_premiums(self):
today = date(2020, 6, 5)
tomorrow = today + timedelta(days=1)
next_year = today + timedelta(days=366)
groceries = Site.objects.create(domain='groceries.com')
catvids = Site.objects.create(domain='catvids.com')
dave = User.objects.create_user('dave')
sally = User.objects.create_user('sally')
Premium.objects.create(user=dave, site=groceries, end=tomorrow)
Premium.objects.create(user=dave, site=groceries, end=next_year)
Premium.objects.create(user=dave, site=catvids, end=tomorrow)
Premium.objects.create(user=sally, site=groceries, end=tomorrow)
Premium.objects.create(user=sally, site=catvids, end=tomorrow)
Premium.objects.create(user=sally, site=catvids, end=next_year)
ending_premiums = get_ending_premiums(today)
ending = set((p.user, p.site) for p in ending_premiums)
self.assertNotIn((dave, groceries), ending)
self.assertIn((dave, catvids), ending)
self.assertIn((sally, groceries), ending)
self.assertNotIn((sally, catvids), ending)
self.assertEqual(2, len(ending_premiums))
I've come up with this... It's got some raw SQL but it still returns a QuerySet with normal QuerySet methods (although it uses the apparently deprecated QuerySet.extra() method)
def get_ending_premiums(day=None):
"""Get a queryset of Premiums for which a user has none following."""
if day is None:
day = date.today()
tomorrow = day + timedelta(days=1)
ending_premiums = Premium.objects.filter(
end=tomorrow,
).extra(
where=['NOT EXISTS (SELECT NULL FROM premium_premium child where premium_premium.site_id = site_id AND premium_premium.user_id = user_id AND end > %s )'],
params=[tomorrow],
)
return ending_premiums
Still wondering if there isn’t a better way...

How to create selection tabs for date and time field in Django?

Have looked through DateField, TimeField, DateTimeField related documents but I cannot seem to find what I need. I simply want to have a selection of month, day, year, hour, minute, (AM/PM) type option. I have tried using 'choice=', but do not get the nice behavior I am looking for.
** TL;DR: I simply want a way of putting in the date and time without having to type it in. I would like a nice drop down menu **
class Event(models.Model):
event_name = models.CharField(max_length = 50)
date_time = models.DateTimeField()
date = models.DateField()
location = models.CharField(max_length = 30)
address = models.CharField(max_length = 30)
city = models.CharField(max_length = 30)
zip_code = models.CharField(max_length = 30)
state = models.CharField(max_length = 30)
description = models.TextField()
def __unicode__(self):
return self.event_name
class EventForm(ModelForm):
class Meta:
model = Event
This is what I currently have. I have removed the choices part and I even tried making my own model object dedicated to date and time, but that did not go well
I tried it using this ...
DATE_CHOICES = (('Jan', "January"),
('Feb', "Feburary"),
('Mar', 'March'),
('Apr','April'),
('May ','May'),
('June','June'),
('July','July'),
('Aug','August'),
('Sept','Septemeber'),
('Oct','October'),
('Nov','November'),
('Dec','December')
)
class DateTime(models.Model):
month = models.CharField(max_length = 5, choices=DATE_CHOICES)
But I am not getting the correct behavior as I want.
You might be interested in using jquery date picker or jquery datetime picker.
http://jqueryui.com/datepicker/
http://trentrichardson.com/examples/timepicker/
On both sites there are exampels so you can see it in action :)
You definitely want to use this snippet. Unless you're a django ninja and want to roll up your own multi widget, which is what you will need to transform a set of select inputs into one datetime value.
This widget is the closest you will get to do it, without using any js plugins.
Your can use datepicker plagin as Erfin mentioned (I recommend it too and also datepicker for bootstrap) for date and masked input for time or just simple selects. Anyway you should send a request with datetime information. What to do in django:
If you use datepicker plugin for date and masked input for time
Let's assume that your request is POST. Your date will be a string with format you specify in javascript. It looks like "31.01.2013". And time will be like "22:30".
def write_datetime(request):
event = Event.objects.get(id=int(request.POST.get('id')))
from datetime.datetime import strptime
date = request.POST.get('date')
time = request.POST.get('time')
date_time = date + " " + time
event.date_time = strptime(date_time, "%d.%m.%y %H:%M"
event.save()
If you use just selects
In this case, it's simplier to make a datetime string from request parameters and repeat the preveous example.
def def write_datetime(request):
year = request.POST.get('year')
month = request.POST.get('month')
# etc
date_time = "%s.%s.%s %s:%s" % (day, month, year, hours, minutes)
# etc

Categories

Resources