Autosave: 20260125-175045
This commit is contained in:
parent
c95591245a
commit
dc2bd62142
Binary file not shown.
Binary file not shown.
@ -11,7 +11,8 @@ from django.shortcuts import render, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from .models import (
|
||||
Tenant, TenantUserRole, InteractionType, DonationMethod, ElectionType, EventType, Voter,
|
||||
VotingRecord, Event, EventParticipation, Donation, Interaction, VoterLikelihood, CampaignSettings
|
||||
VotingRecord, Event, EventParticipation, Donation, Interaction, VoterLikelihood, CampaignSettings,
|
||||
Interest, Volunteer, VolunteerEvent
|
||||
)
|
||||
from .forms import (
|
||||
VoterImportForm, EventImportForm, EventParticipationImportForm,
|
||||
@ -147,6 +148,12 @@ class EventTypeAdmin(admin.ModelAdmin):
|
||||
list_filter = ('tenant', 'is_active')
|
||||
search_fields = ('name',)
|
||||
|
||||
@admin.register(Interest)
|
||||
class InterestAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'tenant')
|
||||
list_filter = ('tenant',)
|
||||
search_fields = ('name',)
|
||||
|
||||
class VotingRecordInline(admin.TabularInline):
|
||||
model = VotingRecord
|
||||
extra = 1
|
||||
@ -163,6 +170,10 @@ class VoterLikelihoodInline(admin.TabularInline):
|
||||
model = VoterLikelihood
|
||||
extra = 1
|
||||
|
||||
class VolunteerEventInline(admin.TabularInline):
|
||||
model = VolunteerEvent
|
||||
extra = 1
|
||||
|
||||
@admin.register(Voter)
|
||||
class VoterAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('first_name', 'last_name', 'nickname', 'voter_id', 'tenant', 'district', 'candidate_support', 'is_targeted', 'city', 'state', 'prior_state')
|
||||
@ -509,6 +520,19 @@ class EventAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
context['opts'] = self.model._meta
|
||||
return render(request, "admin/import_csv.html", context)
|
||||
|
||||
@admin.register(Volunteer)
|
||||
class VolunteerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'email', 'phone', 'tenant', 'user')
|
||||
list_filter = ('tenant',)
|
||||
search_fields = ('name', 'email', 'phone')
|
||||
inlines = [VolunteerEventInline, InteractionInline]
|
||||
filter_horizontal = ('interests',)
|
||||
|
||||
@admin.register(VolunteerEvent)
|
||||
class VolunteerEventAdmin(admin.ModelAdmin):
|
||||
list_display = ('volunteer', 'event', 'role')
|
||||
list_filter = ('event__tenant', 'event', 'role')
|
||||
|
||||
@admin.register(EventParticipation)
|
||||
class EventParticipationAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('voter', 'event', 'participation_type')
|
||||
@ -912,9 +936,9 @@ class DonationAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
|
||||
@admin.register(Interaction)
|
||||
class InteractionAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('id', 'voter', 'type', 'date', 'description')
|
||||
list_filter = ('voter__tenant', 'type', 'date')
|
||||
search_fields = ('voter__first_name', 'voter__last_name', 'voter__voter_id', 'description')
|
||||
list_display = ('id', 'voter', 'volunteer', 'type', 'date', 'description')
|
||||
list_filter = ('voter__tenant', 'type', 'date', 'volunteer')
|
||||
search_fields = ('voter__first_name', 'voter__last_name', 'voter__voter_id', 'description', 'volunteer__name')
|
||||
change_list_template = "admin/interaction_change_list.html"
|
||||
|
||||
def get_urls(self):
|
||||
@ -1308,4 +1332,4 @@ class VoterLikelihoodAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||
@admin.register(CampaignSettings)
|
||||
class CampaignSettingsAdmin(admin.ModelAdmin):
|
||||
list_display = ('tenant', 'donation_goal')
|
||||
list_filter = ('tenant',)
|
||||
list_filter = ('tenant',)
|
||||
@ -0,0 +1,71 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-25 16:33
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0012_voter_prior_state_alter_voter_state'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='tenant',
|
||||
name='description',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='tenant',
|
||||
name='slug',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tenant',
|
||||
name='name',
|
||||
field=models.CharField(max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tenantuserrole',
|
||||
name='role',
|
||||
field=models.CharField(choices=[('admin', 'Admin'), ('campaign_manager', 'Campaign Manager'), ('campaign_staff', 'Campaign Staff')], max_length=20),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Interest',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('tenant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interests', to='core.tenant')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('tenant', 'name')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Volunteer',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('phone', models.CharField(blank=True, max_length=20)),
|
||||
('interests', models.ManyToManyField(blank=True, related_name='volunteers', to='core.interest')),
|
||||
('tenant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='volunteers', to='core.tenant')),
|
||||
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='volunteer_profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interaction',
|
||||
name='volunteer',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interactions', to='core.volunteer'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VolunteerEvent',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('role', models.CharField(max_length=100)),
|
||||
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='volunteers', to='core.event')),
|
||||
('volunteer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='event_assignments', to='core.volunteer')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,24 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-25 16:34
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0013_remove_tenant_description_remove_tenant_slug_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='volunteer',
|
||||
name='assigned_events',
|
||||
field=models.ManyToManyField(related_name='assigned_volunteers', through='core.VolunteerEvent', to='core.event'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='volunteerevent',
|
||||
name='event',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='volunteer_assignments', to='core.event'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
@ -76,6 +76,16 @@ class EventType(models.Model):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Interest(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='interests')
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Voter(models.Model):
|
||||
SUPPORT_CHOICES = [
|
||||
('unknown', 'Unknown'),
|
||||
@ -240,6 +250,26 @@ class Event(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.event_type} on {self.date}"
|
||||
|
||||
class Volunteer(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='volunteers')
|
||||
user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='volunteer_profile')
|
||||
name = models.CharField(max_length=255)
|
||||
email = models.EmailField()
|
||||
phone = models.CharField(max_length=20, blank=True)
|
||||
interests = models.ManyToManyField(Interest, blank=True, related_name='volunteers')
|
||||
assigned_events = models.ManyToManyField(Event, through='VolunteerEvent', related_name='assigned_volunteers')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class VolunteerEvent(models.Model):
|
||||
volunteer = models.ForeignKey(Volunteer, on_delete=models.CASCADE, related_name='event_assignments')
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='volunteer_assignments')
|
||||
role = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.volunteer} at {self.event} as {self.role}"
|
||||
|
||||
class EventParticipation(models.Model):
|
||||
PARTICIPATION_TYPE_CHOICES = [
|
||||
("invited", "Invited"),
|
||||
@ -265,6 +295,7 @@ class Donation(models.Model):
|
||||
|
||||
class Interaction(models.Model):
|
||||
voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='interactions')
|
||||
volunteer = models.ForeignKey(Volunteer, on_delete=models.SET_NULL, null=True, blank=True, related_name='interactions')
|
||||
type = models.ForeignKey(InteractionType, on_delete=models.SET_NULL, null=True)
|
||||
date = models.DateField()
|
||||
description = models.CharField(max_length=255)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user