Fakultas Ilmu Komputer UI
Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Class Project
DIGIPUS
Commits
f0754b70
Commit
f0754b70
authored
May 19, 2020
by
I Gusti Putu Agastya Indrayana
Browse files
Pbi 9 statistik akses materi
parent
3d1f443e
Changes
24
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
f0754b70
...
...
@@ -204,4 +204,5 @@ pip-selfcheck.json
__pycache__/
db.sqlite3
.coverage
htmlcov/
\ No newline at end of file
htmlcov/
flowchart/
\ No newline at end of file
administration/migrations/0004_auto_20200517_1713.py
0 → 100644
View file @
f0754b70
# Generated by Django 3.0.3 on 2020-05-17 10:13
from
django.db
import
migrations
,
models
import
django.utils.timezone
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'administration'
,
'0003_verificationreport_user'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'verificationreport'
,
name
=
'timestamp'
,
field
=
models
.
DateTimeField
(
default
=
django
.
utils
.
timezone
.
now
),
),
]
administration/models.py
View file @
f0754b70
from
django.contrib.postgres.fields
import
JSONField
from
django.db
import
models
from
django.utils
import
timezone
from
app.models
import
VERIFICATION_STATUS
,
Materi
from
authentication.models
import
User
...
...
@@ -15,6 +16,6 @@ class VerificationReport(models.Model):
report
=
JSONField
()
materi
=
models
.
ForeignKey
(
Materi
,
models
.
SET_NULL
,
null
=
True
)
user
=
models
.
ForeignKey
(
User
,
models
.
SET_NULL
,
null
=
True
)
timestamp
=
models
.
DateTimeField
(
auto_now_add
=
True
)
timestamp
=
models
.
DateTimeField
(
default
=
timezone
.
now
)
status
=
models
.
CharField
(
max_length
=
30
,
choices
=
VERIFICATION_STATUS
,
default
=
VERIFICATION_STATUS
[
0
][
0
])
administration/views.py
View file @
f0754b70
...
...
@@ -75,11 +75,9 @@ class DetailVerificationView(TemplateView):
if
action
==
"approve"
and
feedback
!=
""
:
materi
.
status
=
"APPROVE"
materi
.
feedback
=
feedback
materi
.
save
()
elif
action
==
"disapprove"
and
feedback
!=
""
:
materi
.
status
=
"DISAPPROVE"
materi
.
feedback
=
feedback
materi
.
save
()
else
:
context
=
self
.
get_context_data
(
**
kwargs
)
...
...
app/management/commands/__init__.py
0 → 100644
View file @
f0754b70
app/management/commands/generatedummy.py
0 → 100644
View file @
f0754b70
from
datetime
import
datetime
,
timedelta
from
math
import
floor
,
ceil
from
random
import
randint
,
choice
,
choices
,
sample
from
typing
import
List
from
django.core.management.base
import
BaseCommand
from
django.core.files.uploadedfile
import
SimpleUploadedFile
from
django.utils
import
timezone
from
app.models
import
Materi
,
Category
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
from
administration.models
import
VerificationReport
,
VerificationSetting
from
authentication.models
import
User
class
Command
(
BaseCommand
):
help
=
'Generate dummy data for seeding.'
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'num_of_materi'
,
type
=
int
,
help
=
"Number of materi to create"
)
def
_generate_category
(
self
,
num_of_category
:
int
=
5
):
counter
=
0
category_name
=
f
"Kategori dummy
{
counter
}
"
dummy_category
=
[]
for
i
in
range
(
num_of_category
):
while
(
Category
.
objects
.
filter
(
name
=
category_name
).
exists
()):
counter
+=
1
category_name
=
f
"Kategori dummy
{
counter
}
"
category
=
Category
(
name
=
category_name
,
description
=
f
"
{
category_name
}
."
)
category
.
save
()
dummy_category
.
append
(
category
)
return
dummy_category
def
_generate_verifivation_criteria
(
self
,
num_of_criteria
:
int
=
5
):
counter
=
0
criterion_name
=
f
"Kriteria dummy
{
counter
}
"
dummy_criteria
=
[]
for
i
in
range
(
num_of_criteria
):
while
(
VerificationSetting
.
objects
.
filter
(
title
=
criterion_name
).
exists
()):
counter
+=
1
criterion_name
=
f
"Kriteria dummy
{
counter
}
"
criterion
=
VerificationSetting
(
title
=
criterion_name
,
description
=
f
"
{
criterion_name
}
."
)
criterion
.
save
()
dummy_criteria
.
append
(
criterion
)
return
dummy_criteria
def
_generate_cover
(
self
):
cover
=
SimpleUploadedFile
(
"cover.jpg"
,
b
"Test file"
)
return
cover
def
_generate_content
(
self
):
content
=
SimpleUploadedFile
(
"content.txt"
,
b
"Test file"
)
return
content
def
_generate_admin
(
self
,
num_of_user
:
int
=
2
):
counter
=
0
dummy_user
=
[]
email
=
f
"admin-dummy-
{
counter
}
@email.com"
end_date
=
timezone
.
now
()
for
i
in
range
(
num_of_user
):
while
(
User
.
objects
.
filter
(
email
=
email
).
exists
()):
counter
+=
1
email
=
f
"admin-dummy-
{
counter
}
@email.com"
name
=
f
"admin-dummy-
{
counter
}
"
user
=
User
(
email
=
email
,
name
=
name
,
is_admin
=
True
)
user
.
set_password
(
name
)
user
.
date_joined
=
get_time_before
(
timezone
.
now
(),
(
365
*
SECONDS_IN_DAY
))
user
.
save
()
dummy_user
.
append
(
user
)
return
dummy_user
def
_generate_contributor
(
self
,
max_num_of_user
:
int
=
10
):
counter
=
0
dummy_user
=
[]
email
=
f
"kontributor-dummy-
{
counter
}
@email.com"
now
=
timezone
.
now
()
-
timedelta
(
days
=
30
)
last_year
=
timezone
.
now
()
-
timedelta
(
days
=
365
)
dates
=
generate_list_of_random_datetime
(
last_year
,
now
,
max_num_of_user
)
self
.
first_created_contributor
=
dates
[
0
]
for
date_joined
in
dates
:
while
(
User
.
objects
.
filter
(
email
=
email
).
exists
()):
counter
+=
1
email
=
f
"kontributor-dummy-
{
counter
}
@email.com"
name
=
f
"kontributor-dummy-
{
counter
}
"
user
=
User
(
email
=
email
,
name
=
name
,
is_contributor
=
True
)
user
.
set_password
(
name
)
user
.
date_joined
=
date_joined
user
.
save
()
dummy_user
.
append
(
user
)
return
dummy_user
def
_generate_materi
(
self
,
num_of_materi
:
int
):
counter
=
0
materi_name
=
"Materi Dummy {}"
materi_list
=
[]
now
=
timezone
.
now
()
-
timedelta
(
days
=
30
)
dates
=
generate_list_of_random_datetime
(
self
.
first_created_contributor
,
now
,
num_of_materi
)
for
date_created
in
dates
:
contributor
=
choice
(
[
i
for
i
in
self
.
contributors
if
i
.
date_joined
<
date_created
])
while
Materi
.
objects
.
filter
(
title
=
materi_name
.
format
(
counter
)).
exists
():
counter
+=
1
materi
=
Materi
(
title
=
materi_name
.
format
(
counter
),
author
=
contributor
.
name
,
uploader
=
contributor
,
publisher
=
f
"Penerbit
{
contributor
.
name
}
"
,
descriptions
=
f
"Deskripsi
{
materi_name
.
format
(
counter
)
}
."
,
status
=
"PENDING"
,
cover
=
self
.
cover
,
content
=
self
.
content
,
date_created
=
date_created
)
materi
.
save
()
category
=
sample
(
self
.
categories
,
k
=
2
)
materi
.
categories
.
add
(
*
category
)
materi
.
save
()
materi_list
.
append
(
materi
)
# Validasi
status
=
self
.
_get_status
()
if
status
!=
"PENDING"
:
timestamp
=
get_random_datetime
(
date_created
,
date_created
+
timedelta
(
days
=
7
))
admin
=
choice
(
self
.
admins
)
report_field
=
{}
if
status
==
"APPROVE"
:
report_field
=
self
.
_generate_report
(
approved
=
True
)
materi
.
status
=
"APPROVE"
elif
status
==
"DISAPPROVE"
:
report_field
=
self
.
_generate_report
(
approved
=
False
)
materi
.
status
=
"DISAPPROVE"
materi
.
save
()
verif_report
=
VerificationReport
(
report
=
report_field
,
materi
=
materi
,
user
=
admin
,
status
=
materi
.
get_status_display
(),
timestamp
=
timestamp
)
verif_report
.
save
()
else
:
pass
return
materi
def
_verify_count
(
self
,
num_of_materi
:
int
,
reject_rate
:
float
=
0.15
,
pending_rate
:
float
=
0.2
):
num_of_reject
=
floor
(
reject_rate
*
num_of_materi
)
num_of_pending
=
floor
(
pending_rate
*
num_of_materi
)
num_of_approve
=
num_of_materi
-
(
num_of_reject
+
num_of_pending
)
return
(
num_of_reject
,
num_of_pending
,
num_of_approve
)
def
_get_status
(
self
):
choices
=
[]
if
self
.
num_of_approve
>
0
:
choices
.
append
(
"APPROVE"
)
if
self
.
num_of_reject
>
0
:
choices
.
append
(
"DISAPPROVE"
)
if
self
.
num_of_pending
>
0
:
choices
.
append
(
"PENDING"
)
status
=
choice
(
choices
)
if
status
==
"APPROVE"
:
self
.
num_of_approve
-=
1
elif
status
==
"DISAPPROVE"
:
self
.
num_of_reject
-=
1
else
:
self
.
num_of_pending
-=
1
return
status
def
_generate_report
(
self
,
approved
):
report
=
{}
kriteria_list
=
[]
for
kriteria
in
self
.
criteria
:
kriteria_list
.
append
({
"title"
:
kriteria
.
title
,
"status"
:
True
})
if
not
approved
:
n_failed_kriteria
=
randint
(
1
,
len
(
kriteria_list
))
for
i
in
range
(
n_failed_kriteria
):
kriteria_list
[
i
][
"status"
]
=
False
feedback
=
"Materi Dummy tidak diterima karena tidak memenuhi kriteria"
else
:
feedback
=
"Materi Dummy diterima"
report
[
"kriteria"
]
=
kriteria_list
report
[
"feedback"
]
=
feedback
return
report
def
handle
(
self
,
*
args
,
**
options
):
num_of_materi
=
options
[
'num_of_materi'
]
num_of_contributor
=
min
(
floor
(
num_of_materi
*
0.2
),
10
)
num_of_admin
=
ceil
(
num_of_materi
*
0.2
*
0.1
)
self
.
last_contributor_created
=
get_time_before
(
timezone
.
now
(),
(
365
*
SECONDS_IN_DAY
))
self
.
cover
=
self
.
_generate_cover
()
self
.
content
=
self
.
_generate_content
()
self
.
categories
=
self
.
_generate_category
()
self
.
criteria
=
self
.
_generate_verifivation_criteria
()
self
.
num_of_reject
,
self
.
num_of_pending
,
self
.
num_of_approve
=
self
.
_verify_count
(
num_of_materi
)
self
.
admins
=
self
.
_generate_admin
(
num_of_admin
)
self
.
contributors
=
self
.
_generate_contributor
(
num_of_contributor
)
self
.
_generate_materi
(
num_of_materi
)
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
'Successfully created %s materi'
%
options
[
'num_of_materi'
]))
app/management/commands/generatetraffic.py
0 → 100644
View file @
f0754b70
from
datetime
import
datetime
,
timedelta
from
math
import
floor
,
ceil
from
random
import
randint
,
choice
,
choices
,
sample
,
uniform
,
random
from
typing
import
List
from
django.core.management.base
import
BaseCommand
from
django.core.files.uploadedfile
import
SimpleUploadedFile
from
django.utils
import
timezone
from
app.models
import
Materi
,
Comment
,
Like
,
DownloadStatistics
,
ViewStatistics
,
DummyLike
,
DummyViewStatistics
,
DummyDownloadStatistics
,
DummyComment
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
getRandomColor
,
getLoremWithLength
class
Command
(
BaseCommand
):
help
=
'Generate dummy data for seeding.'
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'baseline'
,
type
=
int
,
default
=
100
,
help
=
"Baseline number of visit perday"
)
parser
.
add_argument
(
'--coef-materi'
,
type
=
float
,
default
=
0.10
,
help
=
"Coef number for visit because of materi i.e. more materi = more visit"
)
parser
.
add_argument
(
'--coef-time'
,
type
=
float
,
default
=
0.05
,
help
=
"Coef number for visit because of time i.e. more time = more visit"
)
parser
.
add_argument
(
'--coef-visit-range'
,
type
=
float
,
default
=
0.25
,
help
=
"Coef number for visit because of time i.e. more time = more visit"
)
parser
.
add_argument
(
'--coef-read'
,
type
=
float
,
default
=
0.20
,
help
=
"chance of visiting user to view a materi"
)
parser
.
add_argument
(
'--coef-download'
,
type
=
float
,
default
=
0.5
,
help
=
"chance of viewing user to download a materi"
)
parser
.
add_argument
(
'--coef-like'
,
type
=
float
,
default
=
0.4
,
help
=
"chance of viewing user to like a materi"
)
parser
.
add_argument
(
'--coef-comment'
,
type
=
float
,
default
=
0.2
,
help
=
"chance of viewing user to comment on a materi"
)
def
_view_materi
(
self
,
timestamp
,
materi
):
item
=
ViewStatistics
(
materi
=
materi
,
timestamp
=
timestamp
)
item
.
save
()
DummyViewStatistics
(
item
=
item
).
save
()
def
_download_materi
(
self
,
timestamp
,
materi
):
item
=
DownloadStatistics
(
materi
=
materi
,
timestamp
=
timestamp
)
item
.
save
()
DummyDownloadStatistics
(
item
=
item
).
save
()
def
_like_materi
(
self
,
timestamp
,
materi
):
item
=
Like
(
materi
=
materi
,
timestamp
=
timestamp
,
session_id
=
f
"DuMmY
{
generate_random_string
(
27
)
}
"
)
item
.
save
()
DummyLike
(
item
=
item
).
save
()
def
_comment_materi
(
self
,
timestamp
,
materi
):
item
=
Comment
(
materi
=
materi
,
timestamp
=
timestamp
,
profile
=
getRandomColor
(),
comment
=
getLoremWithLength
(
240
))
item
.
save
()
DummyComment
(
item
=
item
).
save
()
def
handle
(
self
,
*
args
,
**
options
):
materi
=
Materi
.
objects
.
filter
(
title__icontains
=
"dummy"
)
materi
=
[
i
for
i
in
materi
if
i
.
published_date
is
not
None
]
today
=
timezone
.
now
()
materi_published_date
=
[
i
.
published_date
for
i
in
materi
]
materi_published_date
.
sort
()
r_day
=
1
s_date
=
materi_published_date
[
0
]
s_date
=
s_date
.
replace
(
day
=
s_date
.
day
+
1
,
hour
=
0
,
minute
=
0
,
second
=
0
,
microsecond
=
0
)
reports
=
[]
while
(
s_date
<
today
):
report
=
{
"s_date"
:
s_date
,
"visit"
:
0
,
"view"
:
0
,
"download"
:
0
,
"like"
:
0
,
"comment"
:
0
,
}
today_materi
=
[
i
for
i
in
materi
if
i
.
published_date
<
s_date
]
visiting_user
=
options
[
"baseline"
]
visiting_user
+=
int
(
options
[
"coef_time"
]
*
r_day
)
+
\
int
(
options
[
"coef_materi"
]
*
len
(
today_materi
))
visiting_user
=
int
(
visiting_user
*
(
1
+
uniform
(
-
options
[
"coef_visit_range"
],
options
[
"coef_visit_range"
])))
active_user
=
int
(
visiting_user
*
options
[
"coef_read"
])
report
[
"visit"
]
=
visiting_user
report
[
"view"
]
=
active_user
times
=
generate_list_of_random_datetime
(
s_date
,
s_date
+
timedelta
(
days
=
1
),
active_user
)
for
timestamp
in
times
:
selected_materi
=
choice
(
today_materi
)
self
.
_view_materi
(
timestamp
,
selected_materi
)
if
random
()
<
options
[
"coef_download"
]:
self
.
_download_materi
(
timestamp
,
selected_materi
)
report
[
"download"
]
+=
1
if
random
()
<
options
[
"coef_like"
]:
self
.
_like_materi
(
timestamp
,
selected_materi
)
report
[
"like"
]
+=
1
if
random
()
<
options
[
"coef_comment"
]:
self
.
_comment_materi
(
timestamp
,
selected_materi
)
report
[
"comment"
]
+=
1
s_date
=
s_date
+
timedelta
(
days
=
1
)
r_day
+=
1
reports
.
append
(
report
)
# for i in range
for
i
in
reports
:
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"Today is
{
i
[
's_date'
]
}
"
))
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"User visit
{
i
[
'visit'
]
}
"
))
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"User view
{
i
[
'view'
]
}
"
))
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"User download
{
i
[
'download'
]
}
"
))
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"User like
{
i
[
'like'
]
}
"
))
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
f
"User comment
{
i
[
'comment'
]
}
"
))
app/management/commands/removedummy.py
0 → 100644
View file @
f0754b70
from
datetime
import
datetime
from
math
import
floor
from
random
import
randint
,
choice
,
choices
from
typing
import
List
from
django.core.management.base
import
BaseCommand
from
django.core.files.uploadedfile
import
SimpleUploadedFile
from
app.models
import
Materi
,
Category
,
Comment
,
Like
,
DownloadStatistics
,
ViewStatistics
from
administration.models
import
VerificationReport
,
VerificationSetting
from
authentication.models
import
User
class
Command
(
BaseCommand
):
help
=
'Remmove dummy data for seeding.'
def
_remove_user
(
self
):
for
item
in
User
.
objects
.
filter
(
email__icontains
=
"dummy"
):
item
.
delete
()
def
_remove_category
(
self
):
for
item
in
Category
.
objects
.
filter
(
name__icontains
=
"dummy"
):
item
.
delete
()
def
_remove_materi
(
self
):
for
item
in
Materi
.
objects
.
filter
(
title__icontains
=
"dummy"
):
item
.
verificationreport_set
.
all
().
delete
()
item
.
delete
()
def
_remove_verifivation_criteria
(
self
):
for
item
in
VerificationSetting
.
objects
.
filter
(
title__icontains
=
"dummy"
):
item
.
delete
()
def
_remove_verivication_report
(
self
):
for
item
in
VerificationReport
.
objects
.
filter
(
report__feedback__icontains
=
"dummy"
):
item
.
delete
()
def
handle
(
self
,
*
args
,
**
options
):
self
.
_remove_user
()
self
.
_remove_category
()
self
.
_remove_materi
()
self
.
_remove_verifivation_criteria
()
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
'Successfully remove all dummy object'
))
app/management/commands/removetraffic.py
0 → 100644
View file @
f0754b70
from
datetime
import
datetime
,
timedelta
from
math
import
floor
,
ceil
from
random
import
randint
,
choice
,
choices
,
sample
,
uniform
,
random
from
typing
import
List
from
django.core.management.base
import
BaseCommand
from
django.core.files.uploadedfile
import
SimpleUploadedFile
from
django.utils
import
timezone
,
lorem_ipsum
from
app.models
import
DummyLike
,
DummyViewStatistics
,
DummyDownloadStatistics
,
DummyComment
from
app.management.commands.utils
import
SECONDS_IN_DAY
,
get_time_before
,
get_random_datetime
,
generate_list_of_random_datetime
,
generate_random_string
,
getRandomColor
class
Command
(
BaseCommand
):
help
=
'Remmove dummy data for seeding.'
def
_remove_view
(
self
):
for
item
in
DummyViewStatistics
.
objects
.
all
():
item
.
item
.
delete
()
item
.
delete
()
def
_remove_download
(
self
):
for
item
in
DummyDownloadStatistics
.
objects
.
all
():
item
.
item
.
delete
()
item
.
delete
()
def
_remove_like
(
self
):
for
item
in
DummyLike
.
objects
.
all
():
item
.
item
.
delete
()
item
.
delete
()
def
_remove_comment
(
self
):
for
item
in
DummyComment
.
objects
.
all
():
item
.
item
.
delete
()
item
.
delete
()
def
handle
(
self
,
*
args
,
**
options
):
self
.
_remove_view
()
self
.
_remove_download
()
self
.
_remove_like
()
self
.
_remove_comment
()
self
.
stdout
.
write
(
self
.
style
.
SUCCESS
(
'Successfully remove all dummy traffic'
))
app/management/commands/utils.py
0 → 100644
View file @
f0754b70
from
datetime
import
datetime
,
timedelta
from
math
import
floor
,
ceil
from
random
import
randint
,
choice
,
choices
,
sample
,
random
from
string
import
ascii_letters
from
django.utils
import
timezone
,
lorem_ipsum
SECONDS_IN_DAY
=
86400
def
getRandomColor
():
color
=
"%06x"
%
randint
(
0
,
0xFFFFFF
)
return
color
def
getLoremWithLength
(
n
):
while
True
:
s
=
lorem_ipsum
.
sentence
()
if
len
(
s
)
<
n
:
return
s
def
get_time_before
(
datetime
,
delta
):
return
datetime
-
timedelta
(
seconds
=
delta
)
def
get_time_after
(
datetime
,
delta
):
return
datetime
+
timedelta
(
seconds
=
delta
)
def
get_delta_in_seconds
(
s
,
e
):
return
int
((
e
-
s
).
total_seconds
())
def
get_random_datetime
(
start_date
,
end_date
,
max_delta_seconds
=
None
,
min_delta_seconds
=
None
):
delta
=
get_delta_in_seconds
(
start_date
,
end_date
)
lower
=
0
if
min_delta_seconds
is
None
else
min_delta_seconds
upper
=
delta
if
max_delta_seconds
is
None
else
max_delta_seconds
delta
=
randint
(
lower
,
upper
)
return
start_date
+
timedelta
(
seconds
=
delta
)
def
generate_list_of_random_datetime
(
start
,
end
,
n
):
res
=
[]
for
i
in
range
(
n
):
res
.
append
(
get_random_datetime
(
start
,
end
))
res
.
sort
()
return
res
def
get_last_year
():
datetime
=
timezone
.
now
()
-
timedelta
(
days
=
365
)
datetime
=
datetime
.
replace
(
hour
=
0
,
minute
=
0
,
second
=
0
,
microsecond
=
0
)
return
datetime
def
generate_random_string
(
n
):
return
(
''
.
join
(
choice
(
ascii_letters
)
for
i
in
range
(
n
)))
app/migrations/0004_like.py
0 → 100644
View file @
f0754b70
# Generated by Django 3.0.3 on 2020-05-12 08:34
from
django.db
import
migrations
,
models
import
django.db.models.deletion
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'app'
,
'0003_auto_20200509_2108'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'Like'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
auto_created
=
True
,
primary_key
=
True
,
serialize
=
False
,
verbose_name
=
'ID'
)),
(
'timestamp'
,
models
.
DateTimeField
(
auto_now_add
=
True
)),
(
'materi'
,
models
.
ForeignKey
(
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
to
=
'app.Materi'
)),
],
),
]
app/migrations/0005_like_session_id.py
0 → 100644
View file @
f0754b70
# Generated by Django 3.0.3 on 2020-05-12 09:24
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'app'
,
'0004_like'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'like'
,
name
=
'session_id'
,
field
=
models
.
CharField
(
default
=
''
,
max_length
=
32
),
preserve_default
=
False
,
),
]
app/migrations/0006_downloadstatistics_viewstatistics.py
0 → 100644
View file @
f0754b70
# Generated by Django 3.0.3 on 2020-05-13 10:34
from
django.db
import
migrations
,
models
import
django.db.models.deletion