The source code is in questionnaire/models.py.
Logic Design
-
When create task, available_balance should be more than fee * participant_quota.
-
When determine task’s fee, participant_quota should also be determined but not vice versa.
-
Task’s due_date is only w.r.t. participantship’s participanted_date, so participantship’s confirmed_date is unrestricted.
-
When create a participantship, task issuer’s balance is deducted 1 * fee.
-
When task cancelled, task issuer will not be refunded and affect corresponding participantship, participant whose _status == ‘UNDERWAY’ will be paid.
-
Task can be claimed when status == ‘UNDERWAY’ and claimer is not issuer.
-
When task invalid, task issuer will not be refunded and cause corresponding participantship invalid, participant whose _status == ‘UNDERWAY’ will NOT be paid.
-
Only participant has permission to modify _status from ‘UNDERWAY’ to ‘CANCELLED’ and task issuer is refunded 1 * fee.
-
Only task issuer has permission to modify _status from ‘UNDERWAY’ to ‘CONFIRMED’ and participant is paid 1 * fee.
-
Only task issuer has permission to comment when _status == ‘CONFIRMED’.
Status Design
Task statuses:
INVALID : Has certain number of claimers
CANCELLED : Cancelled by issuer
CLOSED : due_date expires
QUOTA FULL : Attain to participant_quota
UNDERWAY : In progress
Participantship statuses:
CANCELLED : Cancelled by participant
COMMENTED : Has been commented by its task issuer
CONFIRMED : Has been confirmed by its task issuer
TASK INVALID : Its task has certain number of claimers
TASK CANCELLED : Its task has been cancelled
UNDERWAY : In progress
Play with The Models
You can first hop into the interactive Python shell and play around with using this command
$ python3 manage.py shell
It will set the DJANGO_SETTINGS_MODULE environment variable.
The following code shows how to manipulate the Django models I design. I will also specify some of them.
# Create User
from questionnaire.models import Profile, Task, Tag, Participantship
from django.contrib.auth.models import User
user4 = User.objects.create_user(
username='user4', email='user4@niffler.com', password='user4')
user4 = User.objects.get(pk=4) # same
Profile.objects.create(user=user4, phone='16666666664')
>>> <Profile: Profile object (4)>
# Reverse Retrieve
user4.profile.phone
>>> '16666666664'
user4.profile.balance
>>> 10000
# Create Task
"""
TODO:
- ensure issuer's balance >= (fee * participant_quota of all his active task)
- ensure participant_quota should be not null when fee is not null
- if someone participant the task, the issuer's balance will deduct 1 * fee
- if issuer cancel the task, actual participants' amount * fee will not be refunded
- the status property will indicate whether it is expired
- the task becomes invalid when claimers' amount exceeds the threshold, actual participants' amount * fee will not be refunded
"""
user1 = User.objects.get(pk=1) # query by pk
task1 = Task(title='What is 1+1?', issuer=user1)
task1.save() # another way to create
user1.issued_tasks.all() # call by related_name
>>> <QuerySet [<Task: Task object (1)>]>
# Convert Time Zone
from pytz import timezone
cst_tz = timezone('Asia/Shanghai')
task1.created_date.astimezone(cst_tz)
>>> datetime.datetime(2019, 6, 2, 16, 6, 41, 797096, tzinfo=<DstTzInfo 'Asia/
Shanghai' CST+8:00:00 STD>)
# Update
task1 = Task.objects.get(pk=1)
task1.title='Why is is 1+1?'
task1.save()
Task.objects.get(pk=1).title
>>> 'Why is is 1+1?'
# Modify auth.User
user3 = User.objects.get(pk=3)
user3.username = 'user3'
user3.email = 'user3@niffler.com'
user3.set_password('user3')
user3.save()
# Verify Password
from django.contrib.auth import authenticate
not not authenticate(username='user3', password='user4')
>>> False
not not authenticate(username='user3', password='user3')
>>> True
# Create Tag
Tag(name='Math').save()
tag1 = Tag.objects.get(name='Math') # query by name
tag1.tasks.add(task1) # error if tag1 is not saved
task1.tag_set.all()
>>> <QuerySet [<Tag: Tag object (1)>]>
tag1.tasks.all()
>>> <QuerySet [<Task: Task object (1)>]>
# Participate Task
"""
TODO:
- issuer should not be participant
- if participant cancel the task, refund issuer 1 * fee
- for simplicity, if issuer confirm the task, participant can obtain 1 * fee, issuer can rate and comment
- for simplicity, the task finished_date is unrelated to due_date
- if the task becomes invalid, participant cannot obtain 1 * fee
"""
Participantship(user=user2, task=task1).save()
user2.participanted_tasks.all()
>>> <QuerySet [<Task: Task object (1)>]>
user2.participantship_set.all()
>>> <QuerySet [<Participantship: Participantship object (1)>]>
task1.participantship_set.all()
>>> <QuerySet [<Participantship: Participantship object (1)>]>
user2.participantship_set.all()[0].participanted_date
>>> datetime.datetime(2019, 6, 2, 9, 16, 1, 489484, tzinfo=<UTC>)