Skip to content

Commit c453ba1

Browse files
authored
Merge pull request #16 from PROCOLLAB-github/dev
Dev
2 parents 1dd70a0 + 3a54ec2 commit c453ba1

17 files changed

Lines changed: 428 additions & 98 deletions

.github/workflows/lints.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
pip install flake8
2727
- name: Analysing the code with flake8
2828
run: |
29-
flake8 $(git ls-files '*.py')
29+
flake8 $(git ls-files '*.py')

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,5 @@ dmypy.json
135135

136136
cache
137137

138-
static
138+
static
139+
staticfiles

projects/admin.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from projects.models import Project, Achievement
3+
from projects.models import Project, Achievement, Collaborator
44

55

66
@admin.register(Project)
@@ -18,3 +18,16 @@ class ProjectAdmin(admin.ModelAdmin):
1818
@admin.register(Achievement)
1919
class AchievementAdmin(admin.ModelAdmin):
2020
list_display = ("id", "title", "status", "project")
21+
22+
23+
@admin.register(Collaborator)
24+
class CollaboratorAdmin(admin.ModelAdmin):
25+
list_display = (
26+
"id",
27+
"user",
28+
"project",
29+
"role",
30+
"datetime_created",
31+
"datetime_updated",
32+
)
33+
list_display_links = ("id", "user", "project")

projects/managers.py

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,43 @@
77

88
class ProjectManager(Manager):
99
def get_projects_for_list_view(self):
10-
return (
11-
self.get_queryset()
12-
.prefetch_related(
13-
Prefetch(
14-
"industry",
15-
queryset=Industry.objects.only("name").all(),
16-
),
17-
Prefetch(
18-
"leader",
19-
queryset=CustomUser.objects.only("id").all(),
20-
),
21-
)
22-
.only(
23-
"id",
24-
"name",
25-
"leader__id",
26-
"description",
27-
"short_description",
28-
"step",
29-
"industry__name",
30-
"image_address",
31-
"draft",
32-
"datetime_created",
33-
)
34-
.all()
10+
return self.get_queryset().prefetch_related(
11+
Prefetch(
12+
"industry",
13+
queryset=Industry.objects.only("name").all(),
14+
),
15+
Prefetch(
16+
"leader",
17+
queryset=CustomUser.objects.only("id").all(),
18+
),
19+
# Prefetch(
20+
# "collaborator_set",
21+
# queryset=Collaborator.objects.filter(
22+
# id__in=Subquery(
23+
# Collaborator.objects
24+
# .filter(project_id=OuterRef('project_id')).values_list('id', flat=True)[:4]
25+
# )
26+
# ),
27+
# to_attr='collaborators'
28+
# ),
29+
# Yes, this fetches the entire collaborator_set even though we only need 4 and the total count.
30+
# No, You can't do it any other way than this.
31+
# Above is a hack that can fetch max 4 vacancies, but if you use it the count will always be <=4.
32+
# To get the count right using the thing above you either have to make another godawful hack,
33+
# Or override the default QuerySet to always ask the DB only count after all the filters.
34+
# (ticket referring to the reason why you can't
35+
# prefetch N items easily https://code.djangoproject.com/ticket/26780)
36+
# (seems like in django 4.2.0 it'll be fixed but at the time of writing the latest version is 4.1.3
37+
Prefetch("collaborator_set"),
3538
)
3639

3740
def get_projects_for_detail_view(self):
3841
return (
39-
self.get_queryset()
40-
.prefetch_related(
41-
"collaborators",
42-
"achievements",
43-
)
44-
.all()
42+
self.get_queryset().prefetch_related("achievements", "collaborator_set").all()
4543
)
4644

4745
def check_if_owns_any_projects(self, user) -> bool:
46+
# I don't think this should work but the function has no usages, so I'll let it be
4847
return user.leader_projects.exists()
4948

5049

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Generated by Django 4.1.2 on 2022-11-04 19:23
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
("projects", "0003_alter_project_collaborators"),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name="Collaborator",
18+
fields=[
19+
(
20+
"id",
21+
models.BigAutoField(
22+
auto_created=True,
23+
primary_key=True,
24+
serialize=False,
25+
verbose_name="ID",
26+
),
27+
),
28+
(
29+
"role",
30+
models.CharField(
31+
blank=True, max_length=1024, null=True, verbose_name="Роль"
32+
),
33+
),
34+
(
35+
"datetime_created",
36+
models.DateTimeField(auto_now_add=True, verbose_name="Дата создания"),
37+
),
38+
(
39+
"datetime_updated",
40+
models.DateTimeField(auto_now=True, verbose_name="Дата изменения"),
41+
),
42+
(
43+
"project",
44+
models.ForeignKey(
45+
on_delete=django.db.models.deletion.CASCADE,
46+
to="projects.project",
47+
verbose_name="Проект",
48+
),
49+
),
50+
(
51+
"user",
52+
models.ForeignKey(
53+
on_delete=django.db.models.deletion.CASCADE,
54+
to=settings.AUTH_USER_MODEL,
55+
verbose_name="Пользователь",
56+
),
57+
),
58+
],
59+
options={
60+
"verbose_name": "Коллаборатор",
61+
"verbose_name_plural": "Коллабораторы",
62+
},
63+
),
64+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 4.1.2 on 2022-11-05 09:06
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
11+
("projects", "0004_collaborator"),
12+
]
13+
14+
operations = [
15+
migrations.RemoveField(
16+
model_name="project",
17+
name="collaborators",
18+
),
19+
20+
migrations.AddConstraint(
21+
model_name="collaborator",
22+
constraint=models.UniqueConstraint(
23+
fields=("project", "user"), name="unique_collaorator"
24+
),
25+
),
26+
]

projects/models.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from django.contrib.auth import get_user_model
22
from django.db import models
3+
from django.db.models import UniqueConstraint
34

45
from industries.models import Industry
56
from projects.helpers import VERBOSE_STEPS
67
from projects.managers import ProjectManager, AchievementManager
8+
from users.models import CustomUser
79

810
User = get_user_model()
911

@@ -22,7 +24,6 @@ class Project(models.Model):
2224
industry: A ForeignKey referring to the Industry model.
2325
presentation_address: A URLField presentation URL address.
2426
image_address: A URLField image URL address.
25-
collaborators: A ManyToManyField collaborators of the project.
2627
leader: A ForeignKey referring to the User model.
2728
draft: A boolean indicating if Project is a draft.
2829
datetime_created: A DateTimeField indicating date of creation.
@@ -45,12 +46,6 @@ class Project(models.Model):
4546
presentation_address = models.URLField(blank=True)
4647
image_address = models.URLField(blank=True)
4748

48-
collaborators = models.ManyToManyField(
49-
User,
50-
related_name="projects",
51-
blank=True,
52-
)
53-
5449
leader = models.ForeignKey(
5550
User,
5651
on_delete=models.SET_NULL,
@@ -105,3 +100,39 @@ def __str__(self):
105100
class Meta:
106101
verbose_name = "Достижение"
107102
verbose_name_plural = "Достижения"
103+
104+
105+
class Collaborator(models.Model):
106+
"""Project collaborator model
107+
108+
Attributes:
109+
user: A ForeignKey referencing the user who is collaborating in the project
110+
project: A ForeignKey referencing the project the user is collaborating in
111+
role: A CharField meaning the role the user is fulfilling in the project
112+
datetime_created: A DateTimeField indicating date of creation.
113+
datetime_updated: A DateTimeField indicating date of update.
114+
"""
115+
116+
user = models.ForeignKey(CustomUser, models.CASCADE, verbose_name="Пользователь")
117+
project = models.ForeignKey(Project, models.CASCADE, verbose_name="Проект")
118+
role = models.CharField("Роль", max_length=1024, blank=True, null=True)
119+
120+
datetime_created = models.DateTimeField(
121+
verbose_name="Дата создания", null=False, auto_now_add=True
122+
)
123+
datetime_updated = models.DateTimeField(
124+
verbose_name="Дата изменения", null=False, auto_now=True
125+
)
126+
127+
class Meta:
128+
verbose_name = "Коллаборатор"
129+
verbose_name_plural = "Коллабораторы"
130+
constraints = [
131+
UniqueConstraint(
132+
fields=[
133+
"project",
134+
"user",
135+
],
136+
name="unique_collaorator",
137+
)
138+
]

0 commit comments

Comments
 (0)