Some changes

This commit is contained in:
Kristofers Solo 2023-06-28 02:27:46 +00:00
parent 9019c76d5a
commit 6759ff4b58
30 changed files with 213 additions and 268 deletions

2
.gitignore vendored
View File

@ -135,3 +135,5 @@ debug
/static/admin/ /static/admin/
/static/fontawesomefree/ /static/fontawesomefree/
config.json config.json
/media/profile_pics/*
!/media/profile_pics/default.jpg

View File

@ -1,5 +1,6 @@
# Generated by Django 4.2.2 on 2023-06-27 12:54 # Generated by Django 4.2.2 on 2023-06-27 16:35
import account.models
import django.contrib.auth.models import django.contrib.auth.models
import django.contrib.auth.validators import django.contrib.auth.validators
from django.db import migrations, models from django.db import migrations, models
@ -17,7 +18,7 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='CustomUser', name='User',
fields=[ fields=[
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
@ -30,6 +31,7 @@ class Migration(migrations.Migration):
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='ID')),
('profile_picture', models.ImageField(default='profile_pics/default.jpg', upload_to=account.models.get_profile_pic_path)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
], ],

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='profile_pic',
field=models.ImageField(default='default.jpg', upload_to='profile_pics/'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0002_customuser_profile_pic'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='profile_pic',
field=models.BinaryField(blank=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0003_alter_customuser_profile_pic'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='profile_pic',
field=models.BinaryField(blank=True, editable=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:33
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0004_alter_customuser_profile_pic'),
]
operations = [
migrations.RenameField(
model_name='customuser',
old_name='profile_pic',
new_name='profile_picture',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0005_rename_profile_pic_customuser_profile_picture'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='profile_picture',
field=models.ImageField(default='profile_pic/default.jpg', upload_to='profile_pics/'),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:43
import account.models
from django.db import migrations, models
import pathlib
class Migration(migrations.Migration):
dependencies = [
('account', '0006_alter_customuser_profile_picture'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='profile_picture',
field=models.ImageField(default=pathlib.PurePosixPath('profile_pic/default.jpg'), upload_to=account.models.get_profile_pic_path),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('fossdb', '0001_initial'),
('auth', '0012_alter_user_first_name_max_length'),
('admin', '0003_logentry_add_action_flag_choices'),
('account', '0007_alter_customuser_profile_picture'),
]
operations = [
migrations.RenameModel(
old_name='CustomUser',
new_name='User',
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('fossdb', '0001_initial'),
('auth', '0012_alter_user_first_name_max_length'),
('admin', '0003_logentry_add_action_flag_choices'),
('account', '0008_rename_customuser_user'),
]
operations = [
migrations.RenameModel(
old_name='User',
new_name='CustomUser',
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 13:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('admin', '0003_logentry_add_action_flag_choices'),
('auth', '0012_alter_user_first_name_max_length'),
('fossdb', '0001_initial'),
('account', '0009_rename_user_customuser'),
]
operations = [
migrations.RenameModel(
old_name='CustomUser',
new_name='User',
),
]

View File

@ -14,7 +14,7 @@ def get_profile_pic_path(instance, filename) -> Path:
class User(AbstractUser): class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name="ID") id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name="ID")
profile_picture = models.ImageField(upload_to=get_profile_pic_path, default=Path("profile_pics", "default.jpg")) profile_picture = models.ImageField(upload_to=get_profile_pic_path, default="profile_pics/default.jpg")
@property @property
def full_name(self): def full_name(self):

View File

@ -20,7 +20,10 @@ class ProjectHostingPlatformInline(admin.TabularInline):
class ProjectAdmin(admin.ModelAdmin): class ProjectAdmin(admin.ModelAdmin):
inlines = [ProjectHostingPlatformInline, ProjectProgrammingLanguageInline] inlines = [ProjectHostingPlatformInline, ProjectProgrammingLanguageInline]
list_display = ("name", "owner", "_languages") list_display = (
"name",
"owner",
)
def _languages(self, object): def _languages(self, object):
return " | ".join([i.programming_language.name for i in object.projectprogramminglanguage_set.all()]) return " | ".join([i.programming_language.name for i in object.projectprogramminglanguage_set.all()])

View File

@ -0,0 +1,28 @@
import django_filters
from django.contrib.auth import get_user_model
from .models import Project
User = get_user_model()
class UserFilter(django_filters.FilterSet):
username = django_filters.CharFilter(lookup_expr="icontains")
class Meta:
model = User
fields = ("username",)
class ProjectFilter(django_filters.FilterSet):
owner = UserFilter()
name = django_filters.CharFilter(lookup_expr="icontains")
description = django_filters.CharFilter(lookup_expr="icontains")
class Meta:
model = Project
fields = (
"owner",
"name",
"description",
)

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from .models import ProjectHostingPlatform, HostingPlatform from .models import HostingPlatform, ProjectHostingPlatform
class HostingPlatformForm(forms.ModelForm): class HostingPlatformForm(forms.ModelForm):

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 12:54 # Generated by Django 4.2.2 on 2023-06-27 16:35
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -75,7 +75,7 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(db_index=True, max_length=100, unique=True)), ('name', models.CharField(db_index=True, max_length=100, unique=True)),
('description', models.TextField(blank=True, default='')), ('description', models.TextField(blank=True, default='')),
('icon', models.ImageField(blank=True, null=True, upload_to='types/icons/')), ('icon', models.ImageField(blank=True, upload_to='types/icons/')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -106,4 +106,12 @@ class Migration(migrations.Migration):
name='tag', name='tag',
field=models.ManyToManyField(blank=True, to='fossdb.tag'), field=models.ManyToManyField(blank=True, to='fossdb.tag'),
), ),
migrations.AddConstraint(
model_name='project',
constraint=models.UniqueConstraint(fields=('owner', 'name'), name='unique_owner_name'),
),
migrations.AddConstraint(
model_name='operatingsystemversion',
constraint=models.UniqueConstraint(fields=('operating_system', 'version'), name='unique_os_version'),
),
] ]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-27 16:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fossdb', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='tag',
name='icon',
field=models.ImageField(blank=True, null=True, upload_to='types/icons/'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-27 18:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fossdb', '0002_alter_tag_icon'),
]
operations = [
migrations.AlterField(
model_name='projectprogramminglanguage',
name='percentage',
field=models.PositiveIntegerField(blank=True, null=True),
),
]

View File

@ -6,7 +6,7 @@ from django.db import models
from .license.models import License from .license.models import License
from .operating_system.models import OperatingSystemVersion from .operating_system.models import OperatingSystemVersion
from .programming_language.models import ProgrammingLanguage, ProjectProgrammingLanguage from .programming_language.models import ProgrammingLanguage
from .tag.models import Tag from .tag.models import Tag
@ -18,7 +18,7 @@ class Project(models.Model):
license = models.ManyToManyField(License, blank=True) license = models.ManyToManyField(License, blank=True)
tag = models.ManyToManyField(Tag, blank=True) tag = models.ManyToManyField(Tag, blank=True)
operating_system = models.ManyToManyField(OperatingSystemVersion, blank=True) operating_system = models.ManyToManyField(OperatingSystemVersion, blank=True)
programming_language = models.ManyToManyField(ProgrammingLanguage, through=ProjectProgrammingLanguage, blank=True) programming_language = models.ManyToManyField(ProgrammingLanguage, through="ProjectProgrammingLanguage", blank=True)
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
@property @property
@ -29,4 +29,15 @@ class Project(models.Model):
return f"/{self.owner}/{self.name}" return f"/{self.owner}/{self.name}"
def __str__(self): def __str__(self):
return f"{self.owner} | {self.name}" return f"{self.owner}/{self.name}"
class Meta:
constraints = (
models.UniqueConstraint(
fields=(
"owner",
"name",
),
name="unique_owner_name",
),
)

View File

@ -17,3 +17,14 @@ class OperatingSystemVersion(models.Model):
def __str__(self): def __str__(self):
return f"{self.operating_system.name} {self.version} {'LTS' if self.is_lts else ''}" return f"{self.operating_system.name} {self.version} {'LTS' if self.is_lts else ''}"
class Meta:
constraints = (
models.UniqueConstraint(
fields=(
"operating_system",
"version",
),
name="unique_os_version",
),
)

View File

@ -11,7 +11,7 @@ class ProgrammingLanguage(models.Model):
class ProjectProgrammingLanguage(models.Model): class ProjectProgrammingLanguage(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE) project = models.ForeignKey("Project", on_delete=models.CASCADE)
programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE) programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE)
percentage = models.PositiveIntegerField() percentage = models.PositiveIntegerField(blank=True, null=True)
def __str__(self): def __str__(self):
return f"{self.project.owner}/{self.project.name} | {self.programming_language} | {self.percentage}%" return f"{self.project.owner}/{self.project.name} | {self.programming_language} | {self.percentage}%"

View File

@ -3,9 +3,9 @@ from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path("", views.index, name="index"), path("", views.ProjectListView.as_view(), name="index"),
path("add/", views.ProjectCreateView.as_view(), name="add-project"), path("add/", views.ProjectCreateView.as_view(), name="add-project"),
path("<str:owner>/<str:project_name>/", views.ProjectDetailView.as_view(), name="project-detail"), path("<str:owner>/<str:project_name>/", views.ProjectDetailView.as_view(), name="project-detail"),
path("<str:owner>/<str:project_name>/update/", views.ProjectUpdateView.as_view(), name="project-update"), path("<str:owner>/<str:project_name>/edit/", views.ProjectUpdateView.as_view(), name="project-update"),
path("<str:owner>/<str:project_name>/delete/", views.ProjectDeleteView.as_view(), name="project-delete"), path("<str:owner>/<str:project_name>/delete/", views.ProjectDeleteView.as_view(), name="project-delete"),
] ]

View File

@ -1,58 +1,67 @@
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db import transaction from django.forms import inlineformset_factory
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import redirect
from django.views.generic import CreateView, DeleteView, DetailView, UpdateView from django.views.generic import CreateView, DeleteView, DetailView, UpdateView
from django_filters.views import FilterView
from .filters import ProjectFilter
from .forms import ProjectForm from .forms import ProjectForm
from .hosting_platform.forms import HostingPlatformForm from .hosting_platform.forms import HostingPlatformForm
from .models import Project from .models import Project
from .programming_language.forms import ProgrammingLanguageForm from .programming_language.forms import ProgrammingLanguageForm
from .programming_language.models import ProjectProgrammingLanguage
ProgrammingLanguageInlineFormset = inlineformset_factory(
Project,
ProjectProgrammingLanguage,
form=ProgrammingLanguageForm,
extra=1,
)
def index(request): class ProjectListView(FilterView):
context = { model = Project
"title": "FOSSDB", template_name = "fossdb/index.html"
"projects": Project.objects.all(), filterset_class = ProjectFilter
} context_object_name = "projects"
return render(request, "fossdb/index.html", context) paginate_by = 10 # optional 10 projects a page
class ProjectCreateView(LoginRequiredMixin, CreateView): class ProjectCreateView(LoginRequiredMixin, CreateView):
model = Project model = Project
form_class = ProjectForm form_class = ProjectForm
template_name = "fossdb/add_project.html" template_name = "fossdb/create_view.html"
login_url = "/login/" login_url = "/login/"
redirect_field_name = "redirect_to" redirect_field_name = "redirect_to"
def form_valid(self, form):
response = None
with transaction.atomic():
form.instance.owner = self.request.user
response = super().form_valid(form)
hosting_platform_form = HostingPlatformForm(self.request.POST, instance=self.object)
if hosting_platform_form.is_valid():
hosting_platform = hosting_platform_form.save(commit=False)
hosting_platform.project = self.object
hosting_platform.save()
# TODO: allow adding multiple languages
programming_language_form = ProgrammingLanguageForm(self.request.POST, instance=self.object)
if programming_language_form.is_valid():
programming_language = programming_language_form.save(commit=False)
programming_language.project = self.object
programming_language.save()
return response
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs) data = super().get_context_data(**kwargs)
context["title"] = "Add project" data["hosting_platform"] = HostingPlatformForm(self.request.POST or None, prefix="hosting")
context["project_form"] = ProjectForm() data["programming_language"] = ProgrammingLanguageInlineFormset(self.request.POST or None, prefix="language")
context["hosting_platform_form"] = HostingPlatformForm() data["empty_form"] = ProgrammingLanguageInlineFormset(prefix="language_empty")
context["programming_language_form"] = ProgrammingLanguageForm() return data
return context
def form_valid(self, form):
context = self.get_context_data()
form.instance.owner = self.request.user
hosting_platform = context["hosting_platform"]
programming_language = context["programming_language"]
self.object = form.save()
if hosting_platform.is_valid():
hosting_platform.instance.project = self.object
hosting_platform.save()
# TODO: allow adding multiple languages
if programming_language.is_valid():
for instance in programming_language.save(commit=False):
instance.project = self.object
instance.save()
programming_language.save_m2m()
if hosting_platform.is_valid() and programming_language.is_valid():
return super().form_valid(form)
else:
return self.render_to_response(self.get_context_data(form=form))
class ProjectDetailView(DetailView): class ProjectDetailView(DetailView):
@ -65,7 +74,7 @@ class ProjectDetailView(DetailView):
class ProjectUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView): class ProjectUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Project model = Project
template_name = "fossdb/update_view.html" template_name = "fossdb/create_view.html"
form_class = ProjectForm form_class = ProjectForm
slug_field = "name" slug_field = "name"
slug_url_kwarg = "project_name" slug_url_kwarg = "project_name"
@ -79,17 +88,11 @@ class ProjectUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
return redirect("index") return redirect("index")
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs) data = super(ProjectUpdateView, self).get_context_data(**kwargs)
if self.request.POST: data["hosting_platform"] = HostingPlatformForm(self.request.POST or None, instance=self.object.projecthostingplatform, prefix="hosting")
context["project_form"] = ProjectForm(self.request.POST, instance=self.object) data["programming_language"] = ProgrammingLanguageInlineFormset(self.request.POST or None, instance=self.object, prefix="language")
context["hosting_platform_form"] = HostingPlatformForm(self.request.POST, instance=self.object) data["empty_form"] = ProgrammingLanguageInlineFormset(prefix="language_empty")
context["programming_language_form"] = ProgrammingLanguageForm(self.request.POST, instance=self.object) return data
else:
context["project_form"] = ProjectForm(instance=self.object)
context["hosting_platform_form"] = HostingPlatformForm(instance=self.object)
context["programming_language_form"] = ProgrammingLanguageForm(instance=self.object)
return context
class ProjectDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView): class ProjectDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):

View File

@ -37,6 +37,7 @@ DEBUG = config["DEBUG"]
INSTALLED_APPS = [ INSTALLED_APPS = [
"account", "account",
"fossdb", "fossdb",
"django_filters",
"django.contrib.admin", "django.contrib.admin",
"django.contrib.auth", "django.contrib.auth",
"django.contrib.contenttypes", "django.contrib.contenttypes",

View File

@ -19,12 +19,11 @@ from django.contrib import admin
from django.urls import include, path from django.urls import include, path
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls),
path("", include("fossdb.urls")), path("", include("fossdb.urls")),
path("", include("account.urls")), path("", include("account.urls")),
# path("", include("django.contrib.auth.urls")), path("", include("django.contrib.auth.urls")),
path("admin/", admin.site.urls),
] ]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -1,14 +0,0 @@
{% extends "layout.html" %}
{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block meta %}{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ project_form.as_p }}
{{ hosting_platform_form.as_table }}
<br />
{{ programming_language_form.as_table }}
<button type="submit">Submit</button>
</form>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "layout.html" %}
{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block meta %}{% endblock %}
{% block content %}
<form method="post" id="project-form">
{% csrf_token %}
{{ form.as_p }}
{{ hosting_platform.management_form }}
{{ hosting_platform.as_table }}
<div id="language-formset">
{{ programming_language.management_form }}
{% for form in programming_language %}<div class="language-form">{{ form.as_table }}</div>{% endfor %}
</div>
<!-- This button will trigger the JS to append another language form -->
<button type="button" id="add-more">+</button>
<!-- Render the empty form, which you'll use as a template for new entries -->
<!-- Wrap it in a container so you can reference it by id and hide it -->
<div id="empty-form" style="display:none;">{{ empty_form.as_table }}</div>
<button type="submit">Submit</button>
</form>
<script>
document.querySelector("#add-more").addEventListener("click", function() {
var formIndex = document.querySelector("#id_language-TOTAL_FORMS").value;
var emptyFormDiv = document.querySelector("#empty-form");
var newFormHTML = emptyFormDiv.innerHTML.replace(/__prefix__/g, formIndex);
var newFormDiv = document.createElement("div");
newFormDiv.className = "language-form";
newFormDiv.innerHTML = newFormHTML;
document.querySelector("#language-formset").append(newFormDiv);
document.querySelector("#id_language-TOTAL_FORMS").value = parseInt(formIndex) + 1;
});
</script>
{% endblock %}

View File

@ -39,7 +39,6 @@
<p>No language</p> <p>No language</p>
{% endfor %} {% endfor %}
</ul> </ul>
<p>{{ project.date_created|date:"d.m.Y, G:i" }}</p>
<button> <button>
<a href="{% url 'project-update' project.owner project.name %}">Update</a> <a href="{% url 'project-update' project.owner project.name %}">Update</a>
</button> </button>

View File

@ -3,6 +3,7 @@
{% block title %}{{ title }}{% endblock %} {% block title %}{{ title }}{% endblock %}
{% block meta %}{% endblock %} {% block meta %}{% endblock %}
{% block content %} {% block content %}
<p>{{ username }}</p>
<button> <button>
<a href="{% url 'add-project' %}">Add Project</a> <a href="{% url 'add-project' %}">Add Project</a>
</button> </button>
@ -10,14 +11,17 @@
<a href="/admin">Admin</a> <a href="/admin">Admin</a>
</button> </button>
<br /> <br />
<form action="get">
{{ filter.form.as_p }}
<button type="submit">Filter</button>
</form>
{% for project in projects %} {% for project in projects %}
<div> <div>
<h2> <a href="{{ project.get_absolute_url }}">{{ project }}</a>
<a href="{{ project.get_absolute_url }}">{{ project.owner }}/{{ project.name }}</a>
</h2>
<p>{{ project.description }}</p>
</div> </div>
<div>{{ project.description }}</div>
<hr />
{% empty %} {% empty %}
<p>No projects yet (</p> <p>No projects found</p>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View File

@ -1,12 +0,0 @@
{% extends "layout.html" %}
{% block title %}Edit {{ project.name }}{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ project_form.as_p }}
{{ hosting_platform_form.as_table }}
<br />
{{ programming_language_form.as_table }}
<button type="submit">Save</button>
</form>
{% endblock %}