feat: Add basic flow to add adoption notices

This commit is contained in:
moanos [he/him] 2024-03-19 18:18:55 +01:00
parent dda400f3ba
commit 8488768687
15 changed files with 94 additions and 236 deletions

View File

@ -12,4 +12,7 @@ debug=True
backend=sqlite3 backend=sqlite3
name=notfellchen name=notfellchen
[locations]
media=./media

View File

@ -11,15 +11,6 @@ class Command(BaseCommand):
@staticmethod @staticmethod
def populate_db(): def populate_db():
rat1 = baker.make_recipe(
'fellchensammlung.rat'
)
rat2 = baker.make_recipe(
'fellchensammlung.rat'
)
cat = baker.make_recipe(
'fellchensammlung.cat'
)
rescue1 = baker.make_recipe( rescue1 = baker.make_recipe(
'fellchensammlung.rescue_org' 'fellchensammlung.rescue_org'
) )
@ -27,9 +18,13 @@ class Command(BaseCommand):
'fellchensammlung.rescue_org' 'fellchensammlung.rescue_org'
) )
baker.make(AdoptionNotice, name="Vermittung1", animals=[rat1, rat2], organization=rescue1) adoption1 = baker.make(AdoptionNotice, name="Vermittung1", organization=rescue1)
baker.make(AdoptionNotice, name="Vermittung2", animals=[cat], organization=rescue2) adoption2 = baker.make(AdoptionNotice, name="Vermittung2", organization=rescue2)
rat1 = baker.make(Animal, name="Rat1", adoption_notice=adoption1)
rat2 = baker.make(Animal, name="Rat2", adoption_notice=adoption1)
cat1 = baker.make(Animal, name="Cat1", adoption_notice=adoption1)
User.objects.create_user('test', password='foobar') User.objects.create_user('test', password='foobar')
User.objects.create_superuser(username="admin", password="admin") User.objects.create_superuser(username="admin", password="admin")

View File

@ -1,73 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-17 22:05
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Location',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('postcode', models.CharField(max_length=200)),
('country', models.CharField(choices=[('DE', 'Germany'), ('AT', 'Austria'), ('CH', 'Switzerland')], max_length=20)),
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
],
),
migrations.CreateModel(
name='Species',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Enter a animal species', max_length=200, verbose_name='Name')),
],
options={
'verbose_name': 'Species',
'verbose_name_plural': 'Species',
},
),
migrations.CreateModel(
name='RescueOrganization',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('trusted', models.BooleanField(default=False, verbose_name='Trusted')),
('instagram', models.URLField(blank=True, null=True, verbose_name='Instagram profile')),
('facebook', models.URLField(blank=True, null=True, verbose_name='Facebook profile')),
('fediverse_profile', models.URLField(blank=True, null=True, verbose_name='Fediverse profile')),
('website', models.URLField(blank=True, null=True, verbose_name='Website')),
('location', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='fellchensammlung.location')),
],
),
migrations.CreateModel(
name='AdoptionNotice',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateField(verbose_name='Created at')),
('searching_since', models.DateField(verbose_name='Searching for a home since')),
('name', models.CharField(max_length=200)),
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
('further_information', models.URLField(blank=True, null=True, verbose_name='Link to further information')),
('group_only', models.BooleanField(default=False, verbose_name='Only group adoption')),
('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='fellchensammlung.rescueorganization', verbose_name='Organization')),
],
),
migrations.CreateModel(
name='Animal',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Date of birth')),
('name', models.CharField(max_length=200)),
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
('adoption_notice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fellchensammlung.adoptionnotice')),
('species', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='fellchensammlung.species')),
],
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-18 09:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='animal',
name='adoption_notice',
),
migrations.AddField(
model_name='adoptionnotice',
name='animals',
field=models.ManyToManyField(to='fellchensammlung.animal'),
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-18 13:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0002_remove_animal_adoption_notice_adoptionnotice_animals'),
]
operations = [
migrations.CreateModel(
name='MarkdownContent',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
('content', models.TextField()),
],
options={
'verbose_name_plural': 'Markdown content',
},
),
]

View File

@ -1,36 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-18 16:08
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0003_markdowncontent'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Image',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200)),
('image', models.ImageField(upload_to='images')),
('alt_text', models.TextField(max_length=2000)),
('uploaded_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='adoptionnotice',
name='photos',
field=models.ManyToManyField(blank=True, to='fellchensammlung.image'),
),
migrations.AddField(
model_name='animal',
name='photos',
field=models.ManyToManyField(blank=True, to='fellchensammlung.image'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-19 04:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0004_image_adoptionnotice_photos_animal_photos'),
]
operations = [
migrations.AddField(
model_name='animal',
name='sex',
field=models.CharField(choices=[('M_N', 'male_neutered'), ('M', 'male'), ('F_N', 'female_neutered'), ('F', 'female')], default='female', max_length=20),
preserve_default=False,
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 5.0.3 on 2024-03-19 04:51
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0005_animal_sex'),
]
operations = [
migrations.AlterField(
model_name='animal',
name='date_of_birth',
field=models.DateField(default=datetime.datetime(2024, 3, 19, 4, 51, 44, 367516, tzinfo=datetime.timezone.utc), verbose_name='Date of birth'),
preserve_default=False,
),
]

View File

@ -63,6 +63,25 @@ class RescueOrganization(models.Model):
website = models.URLField(null=True, blank=True, verbose_name=_('Website')) website = models.URLField(null=True, blank=True, verbose_name=_('Website'))
class AdoptionNotice(models.Model):
def __str__(self):
return f"{self.name}"
created_at = models.DateField(verbose_name=_('Created at'), default=datetime.now)
searching_since = models.DateField(verbose_name=_('Searching for a home since'))
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True, verbose_name=_('Description'))
organization = models.ForeignKey(RescueOrganization, blank=True, null=True, on_delete=models.SET_NULL,
verbose_name=_('Organization'))
further_information = models.URLField(null=True, blank=True, verbose_name=_('Link to further information'))
group_only = models.BooleanField(default=False, verbose_name=_('Only group adoption'))
photos = models.ManyToManyField(Image, blank=True)
@property
def animals_list(self):
return self.animals.all()
class Animal(models.Model): class Animal(models.Model):
MALE_NEUTERED = "M_N" MALE_NEUTERED = "M_N"
MALE = "M" MALE = "M"
@ -81,6 +100,7 @@ class Animal(models.Model):
species = models.ForeignKey(Species, on_delete=models.PROTECT) species = models.ForeignKey(Species, on_delete=models.PROTECT)
photos = models.ManyToManyField(Image, blank=True) photos = models.ManyToManyField(Image, blank=True)
sex = models.CharField(max_length=20, choices=SEX_CHOICES, ) sex = models.CharField(max_length=20, choices=SEX_CHOICES, )
adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE)
def __str__(self): def __str__(self):
return f"{self.name}" return f"{self.name}"
@ -99,26 +119,6 @@ class Animal(models.Model):
return reverse('animal-detail', args=[str(self.id)]) return reverse('animal-detail', args=[str(self.id)])
class AdoptionNotice(models.Model):
def __str__(self):
return f"{self.name}"
created_at = models.DateField(verbose_name=_('Created at'))
searching_since = models.DateField(verbose_name=_('Searching for a home since'))
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True, verbose_name=_('Description'))
organization = models.ForeignKey(RescueOrganization, blank=True, null=True, on_delete=models.SET_NULL,
verbose_name=_('Organization'))
further_information = models.URLField(null=True, blank=True, verbose_name=_('Link to further information'))
group_only = models.BooleanField(default=False, verbose_name=_('Only group adoption'))
animals = models.ManyToManyField(Animal)
photos = models.ManyToManyField(Image, blank=True)
@property
def animals_list(self):
return self.animals.all()
class MarkdownContent(models.Model): class MarkdownContent(models.Model):
""" """
Base class to store markdown content Base class to store markdown content

View File

@ -1,6 +0,0 @@
{% extends "fellchensammlung/base_generic.html" %}
{% load i18n %}
{% block content %}
Work in Progress: Vermitteln
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "fellchensammlung/base_generic.html" %}
{% load i18n %}
{% block content %}
<h1>Vermitteln</h1>
Bitte mach dich zunächst mit unseren Regeln vertraut. Dann trage hier die ersten Informationen ein.
Du bekommst in einem weiteren Schritt die Möglichkeit einzelne Tiere zu deiner Vermittlung hinzuzufügen und Fotos hochzuladen.
<form method = "post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Weiter</button>
</form>
{% endblock %}

View File

@ -7,11 +7,17 @@ urlpatterns = [
# ex: /animal/5/ # ex: /animal/5/
path("<int:animal_id>/", views.animal_detail, name="animal-detail"), path("<int:animal_id>/", views.animal_detail, name="animal-detail"),
# ex: /adoption_notice/7/ # ex: /adoption_notice/7/
path("<int:adoption_notice_id>/", views.adoption_notice_detail, name="adoption-notice-detail"), path("vermittlung/<int:adoption_notice_id>/", views.adoption_notice_detail, name="adoption-notice-detail"),
# ex: /search/ # ex: /search/
path("suchen/", views.search, name="search"), path("suchen/", views.search, name="search"),
# ex: /vermitteln/ # ex: /vermitteln/
path("vermitteln/", views.add_adoption, name="add-adoption"), path("vermitteln/", views.add_adoption, name="add-adoption"),
# ex: vermitteln-tiere-hinzufügen/5
path("vermitteln-tiere-hinzufügen/<int:adoption_notice_id>",
views.add_animal_to_adoption,
name="add-animal-to-adoption"),
path("ueber-uns/", views.about, name="about"), path("ueber-uns/", views.about, name="about"),
] ]

View File

@ -1,8 +1,10 @@
from django.shortcuts import render from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.urls import reverse
import markdown import markdown
from django.http import HttpResponse
from fellchensammlung.models import AdoptionNotice, MarkdownContent, Animal from fellchensammlung.models import AdoptionNotice, MarkdownContent, Animal
from .forms import AdoptionNoticeForm, AnimalForm
def index(request): def index(request):
@ -22,12 +24,42 @@ def animal_detail(request, animal_id):
context = {"animal": animal} context = {"animal": animal}
return render(request, 'fellchensammlung/detail_animal.html', context=context) return render(request, 'fellchensammlung/detail_animal.html', context=context)
def search(request): def search(request):
latest_adoption_list = AdoptionNotice.objects.order_by("-created_at")[:5] latest_adoption_list = AdoptionNotice.objects.order_by("-created_at")[:5]
context = {"adoption_notices": latest_adoption_list} context = {"adoption_notices": latest_adoption_list}
return render(request, 'fellchensammlung/search.html', context=context) return render(request, 'fellchensammlung/search.html', context=context)
def add_adoption(request): def add_adoption(request):
return render(request, 'fellchensammlung/add_adoption.html') if request.method == 'POST':
form = AdoptionNoticeForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save()
return redirect(reverse("add-animal-to-adoption", args=[instance.pk]))
else:
form = AdoptionNoticeForm()
return render(request, 'fellchensammlung/form_add_adoption.html', {'form': form})
def add_animal_to_adoption(request, adoption_notice_id):
if request.method == 'POST':
form = AnimalForm(request.POST, request.FILES)
if form.is_valid():
form.cleaned_data["adoption_notice_id"] = adoption_notice_id
instance = form.save(commit=False)
instance.adoption_notice_id = adoption_notice_id
instance.save()
if "button_add_another_animal" in request.POST:
return redirect(reverse("add-animal-to-adoption", args=[str(adoption_notice_id)]))
else:
return redirect(reverse("adoption-notice-detail", args=[str(adoption_notice_id)]))
else:
form = AnimalForm()
return render(request, 'fellchensammlung/form_add_animal_to_adoption.html', {'form': form})
def about(request): def about(request):
md = markdown.Markdown(extensions=["fenced_code"]) md = markdown.Markdown(extensions=["fenced_code"])
@ -39,4 +71,3 @@ def about(request):
"fellchensammlung/about.html", "fellchensammlung/about.html",
context=context context=context
) )

View File

@ -91,6 +91,9 @@ SEC_POLICY = config.get("security", "Policy",
""" LOCATIONS """ """ LOCATIONS """
STATIC_ROOT = config.get("locations", "static", fallback="/notfellchen/static") STATIC_ROOT = config.get("locations", "static", fallback="/notfellchen/static")
MEDIA_ROOT = config.get("locations", "media", fallback="/notfellchen/static")
MEDIA_URL = '/media/'
# see https://docs.djangoproject.com/en/3.2/ref/settings/#std-setting-ALLOWED_HOSTS # see https://docs.djangoproject.com/en/3.2/ref/settings/#std-setting-ALLOWED_HOSTS
ALLOWED_HOSTS = [config.get("notfellchen", "host", fallback='*')] ALLOWED_HOSTS = [config.get("notfellchen", "host", fallback='*')]

View File

@ -16,8 +16,15 @@ Including another URLconf
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [ urlpatterns = [
path("", include("fellchensammlung.urls")), path("", include("fellchensammlung.urls")),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
] ]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)