class Course:
def __init__(self, name, classroom, instructor, day, start_time, end_time):
self.name = name
self.classroom = classroom
self.instructor = instructor
self.day = day
self.start_time = start_time
self.end_time = end_time
class Schedule:
def __init__(self):
self.courses = []
program = [["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"]]
def add_course(self, course):
self.courses.append(course)
def print_schedule(self):
days = ["Monday","Tuesday","Wednesday","Thursday","Friday"]
program = [["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"],["9","10","11","12","13","14","15","16","17"]]
for course in self.courses:
for j in range(course.start_time-9,course.end_time-8):
program[days.index(course.day)][j] += f" {course.name} class from {course.instructor} at {course.classroom}"
for i in range(len(days)):
print(days[i],":")
for k in program[i]:
print(k)
schedule = Schedule()
schedule.add_course(Course("Physics","MED A11","James","Monday",9,11))
schedule.add_course(Course("Logic Design","EEB 4105","Jack","Wednesday",9,10))
schedule.add_course(Course("Logic Design","EEB 4205","Jack","Wednesday",15,17))
schedule.print_schedule()
Here I wanted to create an weekly schedule, I want it to write something when two classes collide. So their self.day need to be same and the times need to intersect.
For times I can do something like
time = {for i in range(start_time,end_time+1)}
if time1.intersection(time2) != 0:
#...
But I don't know how to reach 2 different Course elements at the same time. Also would be great if you have any suggestions for this code.
You can add a method to the Course class that checks it against another Course to see if they collide. When you add a course, have it loop through the existing courses to see if it collides with the existing courses in your Schedule.
class Course:
def __init__(self, name, classroom, instructor, day, start_time, end_time):
self.name = name
self.classroom = classroom
self.instructor = instructor
self.day = day
self.start_time = start_time
self.end_time = end_time
def check_collision(self, other):
if self.day == other.day:
if other.start_time < self.start_time < other.end_time:
return True
if other.start_time < self.end_time < other.end_time:
return True
if self.start_time < other.start_time < self.end_time:
return True
if self.start_time < other.end_time < self.end_time:
return True
return False
class Schedule:
def __init__(self):
self.courses = []
self.program = [
["9","10","11","12","13","14","15","16","17"],
["9","10","11","12","13","14","15","16","17"],
["9","10","11","12","13","14","15","16","17"],
["9","10","11","12","13","14","15","16","17"],
["9","10","11","12","13","14","15","16","17"],
]
def add_course(self, course):
for c in self.courses:
if course.check_collision(c):
print(f'New course has collision with course: {c.name} on {c.day}: {c.start_time}-{c.end_time}')
break
else:
self.courses.append(course)
def print_schedule(self):
days = ["Monday","Tuesday","Wednesday","Thursday","Friday"]
program = [x.copy() for x in self.program]
for course in self.courses:
for j in range(course.start_time-9,course.end_time-8):
program[days.index(course.day)][j] += f" {course.name} class from {course.instructor} at {course.classroom}"
for i in range(len(days)):
print(days[i],":")
for k in program[i]:
print(k)
So based on your Code, what you can do is define a compare function for the class Schedule, you make a Schedule object to hold many courses. So if you want to access a course within a Schedule you need to do schedule.courses[i]. But I suggest you add the following function to the courses class to solve your problem.
def compare_course(self, other_course):
my_time = {i for i in range(start_time, end_time+1)}
other_time = {i for i in range(other_course.start_time, other_course.end_time+1)}
if my_time.intersection(other_course.time) != set():
return "Course Collides"
else:
return "Course does not collide"
I have a question about accessing the object class from the list in python, I have compared my cases to the questions that were on stack overflow but that didn't work. I present the problem as follows
Class Booking has the properties start_date, end_date
from datetime import *
class Booking:
def __init__(self):
self.year = int(input("Enter the Year: "))
self.month = int(input("Enter the Month: "))
self.day = int(input("Enter the Day: "))
self.start_date = datetime.now()
self.end_date = datetime(self.year, self.month, self.day)
Class Room is abstract class
I create a booking(list) to store the object of the Booking class which is initialized when the Room class is initialized.
from abc import *
from booking import Booking
class Room(ABC):
bookings = []
def __init__(self, price, capacity):
self.booking = Booking()
self.price = price
self.capacity = capacity
self.bookings.append(self.booking)
#abstractmethod
def is_booked(self, start_date, end_date):
pass
SingleBed inherits Room(ABC) with price = 150 and capachity =2
from room import Room
class Singlebed(Room):
def __init__(self):
super(Singlebed, self).__init__(150, 2)
def is_booked(self, start_date, end_date):
if start_date >= end_date:
print("EndDate must be greater than StartDate")
is_Booked = False
for check_booking in self.bookings:
is_Booked = check_booking... (I wants to access objects.end_date in class Booking is saved in bookings)
single1 = Singlebed()
single2 = Singlebed()
single3 = Singlebed()
single4 = Singlebed()
single5 = Singlebed()
My question: How do I access object.end_date which is initialized with single1, single2, ...
You are iterating over your self.bookings so "check_booking" is your Booking instance and contains the attribute start_date, end_date, year, month, day
def is_booked(self, start_date, end_date):
if start_date >= end_date:
print("EndDate must be greater than StartDate")
is_Booked = False
for check_booking in self.bookings:
is_Booked = check_booking.start_date
I have the following code in accounts/signals/__init__.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
from orders.models import Order
from accounts.models import Balance
#receiver(post_save, sender=Order)
def update_referral_balance(sender, **kwargs):
if len(sender.user.referrals_set.all()):
# TODO: Add referralTransaction
new_referral_revenue = sender.user.referrals_set.get().revenue
revenue_from_trade = \
new_referral_revenue - sender.old_referral_revenue
balance, created = \
Balance.objects.get(user=sender.user, currency=sender.currency)
balance.balance += revenue_from_trade
balance.save()
Now, when running tests I am getting the following
error:======================================================================
ERROR: test_orders_with_approved_payments (payments.tests.test_views.PaymentReleaseTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/pipeline/source/payments/tests/test_views.py", line 75, in setUp
self.order.save()
File "/pipeline/source/orders/models.py", line 63, in save
super(Order, self).save(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/safedelete/models.py", line 64, in save
super(Model, self).save(**kwargs)
File "/usr/local/lib/python3.5/site-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python3.5/site-packages/django/db/models/base.py", line 745, in save_base
update_fields=update_fields, raw=raw, using=using)
File "/usr/local/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 192, in send
response = receiver(signal=self, sender=sender, **named)
File "/pipeline/source/accounts/signals/__init__.py", line 9, in update_referral_balance
if len(sender.user.referral_set.all()):
AttributeError: 'ForwardManyToOneDescriptor' object has no attribute 'referral_set'
And indeed, when running through it in debugger, I see that the sender.user attribute is something of instance ForwardManyToOneDescriptor:
ipdb> pprint(sender.__dict__['user'].__dict__)
{'cache_name': '_user_cache',
'field': <django.db.models.fields.related.ForeignKey: user>}
What am I doing wrong?
EDIT: My Order Model:
class Order(TimeStampedModel, SoftDeletableModel, UniqueFieldMixin):
USD = "USD"
RUB = "RUB"
EUR = "EUR"
BUY = 1
SELL = 0
TYPES = (
(SELL, 'SELL'),
(BUY, 'BUY'),
)
# Todo: inherit from BTC base?, move lengths to settings?
order_type = models.IntegerField(choices=TYPES, default=BUY)
amount_cash = models.DecimalField(max_digits=12, decimal_places=2)
amount_btc = models.DecimalField(max_digits=18, decimal_places=8)
currency = models.ForeignKey(Currency)
payment_window = models.IntegerField(default=settings.PAYMENT_WINDOW)
user = models.ForeignKey(User, related_name='orders')
is_paid = models.BooleanField(default=False)
is_released = models.BooleanField(default=False)
is_completed = models.BooleanField(default=False)
is_failed = models.BooleanField(default=False)
unique_reference = models.CharField(
max_length=settings.UNIQUE_REFERENCE_LENGTH, unique=True)
admin_comment = models.CharField(max_length=200)
payment_preference = models.ForeignKey('payments.PaymentPreference',
default=None,
null=True)
class Meta:
ordering = ['-created_on']
def save(self, *args, **kwargs):
self.unique_reference = \
self.gen_unique_value(
lambda x: get_random_string(x),
lambda x: Order.objects.filter(unique_reference=x).count(),
settings.UNIQUE_REFERENCE_LENGTH
)
self.convert_coin_to_cash()
if 'is_completed' in kwargs and\
kwargs['is_completed'] and\
not self.is_completed:
self.old_referral_revenue = \
self.user.referral_set.get().revenue
super(Order, self).save(*args, **kwargs)
def convert_coin_to_cash(self):
self.amount_btc = Decimal(self.amount_btc)
queryset = Price.objects.filter().order_by('-id')[:2]
price_sell = [price for price in queryset if price.type == Price.SELL]
price_buy = [price for price in queryset if price.type == Price.BUY]
# Below calculation affect real money the client pays
assert all([len(price_sell),
price_sell[0].price_usd,
price_buy[0].price_rub,
price_buy[0].price_eur])
assert all([len(price_buy),
price_buy[0].price_usd,
price_buy[0].price_rub,
price_buy[0].price_eur])
# TODO: Make this logic more generic,
# TODO: migrate to using currency through payment_preference
# SELL
self.amount_cash = Decimal(self.amount_btc)
if self.order_type == Order.SELL and self.currency.code == Order.USD:
self.amount_cash *= price_buy[0].price_usd
elif self.order_type == Order.SELL and self.currency.code == Order.RUB:
self.amount_cash *= price_buy[0].price_rub
elif self.order_type == Order.SELL and self.currency.code == Order.EUR:
self.amount_cash *= price_buy[0].price_eur
# BUY
if self.order_type == Order.BUY and self.currency.code == Order.USD:
self.amount_cash *= price_sell[0].price_usd
elif self.order_type == Order.BUY and self.currency.code == Order.RUB:
self.amount_cash *= price_sell[0].price_rub
elif self.order_type == Order.BUY and self.currency.code == Order.EUR:
self.amount_cash *= price_sell[0].price_eur
self.amount_cash = money_format(self.amount_cash)
#property
def is_buy(self):
return self.order_type
#property
def payment_deadline(self):
"""returns datetime of payment_deadline (creation + payment_window)"""
# TODO: Use this for pay until message on 'order success' screen
return self.created_on + timedelta(minutes=self.payment_window)
#property
def expired(self):
"""Is expired if payment_deadline is exceeded and it's not paid yet"""
# TODO: validate this business rule
# TODO: Refactor, it is unreasonable to have different standards of
# time in the DB
return (timezone.now() > self.payment_deadline) and\
(not self.is_paid) and not self.is_released
#property
def payment_status_frozen(self):
"""return a boolean indicating if order can be updated
Order is frozen if it is expired or has been paid
"""
# TODO: validate this business rule
return self.expired or \
(self.is_paid and
self.payment_set.last() and
self.payment_set.last().
payment_preference.
payment_method.is_internal)
#property
def withdrawal_address_frozen(self):
"""return bool whether the withdraw address can
be changed"""
return self.is_released
#property
def has_withdraw_address(self):
"""return a boolean indicating if order has a withdraw adrress defined
"""
# TODO: Validate this business rule
return len(self.address_set.all()) > 0
#property
def withdraw_address(self):
addr = None
if self.has_withdraw_address:
addr = self.transaction_set.first().address_to.address
return addr
def __str__(self):
return "{} {} {} BTC {} {}".format(self.user.username or
self.user.profile.phone,
self.order_type,
self.amount_btc,
self.amount_cash,
self.currency)
The sender argument is the model class the signal has connected to. As you can see from the signals docs, in post_save the instance is passed in a separate argument unsurprisingly called instance.
You should write your handler like this:
#receiver(post_save, sender=Order)
def update_referral_balance(sender, instance, **kwargs):
if len(instance.user.referrals_set.all()):
etc, changing sender to instance throughout.
I might be blind, but I really can't see why this class fails with:
AttributeError: NextSunday instance has no attribute 'trigger'
from datetime import datetime
from datetime import time
from datetime import timedelta
class NextSunday():
def __init__(self, trigger=None):
"""
Get date of, and number of days until, next Sunday.
Arguments:
- `trigger`: Add an extra week if less than trigger number of days.
"""
self.str = u'%s (%s days)' % (self.date().date(), self.no_days())
self.trigger = trigger
def __unicode__(self):
return self.str
def __str__(self):
return unicode(self).encode('utf-8')
def __repr__(self):
return '<Next Sunday: ' + self.str + '>'
def no_days(self):
"""Get date of next sunday. """
days = None
for i in range(7):
dt = datetime.now() + timedelta(days=i)
if dt.weekday() == 6:
days = i
# Add another week if there are less days left then trigger
if self.trigger:
if days < self.trigger:
days += 7
return days
def date(self):
# The datetime obj contains the next sunday, but also the current time
dt_of_next_sun = datetime.now() + timedelta(days=self.no_days())
# Get the whole day
date_of_next_sun = datetime.combine(dt_of_next_sun.date(),
time(23, 59))
return date_of_next_sun
You need to switch these
self.str = u'%s (%s days)' % (self.date().date(), self.no_days())
self.trigger = trigger
like this
self.trigger = trigger
self.str = u'%s (%s days)' % (self.date().date(), self.no_days())
because otherwise the no_days method is called before the self.trigger attribute is created. This is bad because the no_days method tries to read the value of the self.trigger attribute:
if self.trigger:
if days < self.trigger: