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 django.template.response import TemplateResponse
|
||||||
from .models import (
|
from .models import (
|
||||||
Tenant, TenantUserRole, InteractionType, DonationMethod, ElectionType, EventType, Voter,
|
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 (
|
from .forms import (
|
||||||
VoterImportForm, EventImportForm, EventParticipationImportForm,
|
VoterImportForm, EventImportForm, EventParticipationImportForm,
|
||||||
@ -147,6 +148,12 @@ class EventTypeAdmin(admin.ModelAdmin):
|
|||||||
list_filter = ('tenant', 'is_active')
|
list_filter = ('tenant', 'is_active')
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
@admin.register(Interest)
|
||||||
|
class InterestAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'tenant')
|
||||||
|
list_filter = ('tenant',)
|
||||||
|
search_fields = ('name',)
|
||||||
|
|
||||||
class VotingRecordInline(admin.TabularInline):
|
class VotingRecordInline(admin.TabularInline):
|
||||||
model = VotingRecord
|
model = VotingRecord
|
||||||
extra = 1
|
extra = 1
|
||||||
@ -163,6 +170,10 @@ class VoterLikelihoodInline(admin.TabularInline):
|
|||||||
model = VoterLikelihood
|
model = VoterLikelihood
|
||||||
extra = 1
|
extra = 1
|
||||||
|
|
||||||
|
class VolunteerEventInline(admin.TabularInline):
|
||||||
|
model = VolunteerEvent
|
||||||
|
extra = 1
|
||||||
|
|
||||||
@admin.register(Voter)
|
@admin.register(Voter)
|
||||||
class VoterAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
class VoterAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||||
list_display = ('first_name', 'last_name', 'nickname', 'voter_id', 'tenant', 'district', 'candidate_support', 'is_targeted', 'city', 'state', 'prior_state')
|
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
|
context['opts'] = self.model._meta
|
||||||
return render(request, "admin/import_csv.html", context)
|
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)
|
@admin.register(EventParticipation)
|
||||||
class EventParticipationAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
class EventParticipationAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||||
list_display = ('voter', 'event', 'participation_type')
|
list_display = ('voter', 'event', 'participation_type')
|
||||||
@ -912,9 +936,9 @@ class DonationAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(Interaction)
|
@admin.register(Interaction)
|
||||||
class InteractionAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
class InteractionAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
||||||
list_display = ('id', 'voter', 'type', 'date', 'description')
|
list_display = ('id', 'voter', 'volunteer', 'type', 'date', 'description')
|
||||||
list_filter = ('voter__tenant', 'type', 'date')
|
list_filter = ('voter__tenant', 'type', 'date', 'volunteer')
|
||||||
search_fields = ('voter__first_name', 'voter__last_name', 'voter__voter_id', 'description')
|
search_fields = ('voter__first_name', 'voter__last_name', 'voter__voter_id', 'description', 'volunteer__name')
|
||||||
change_list_template = "admin/interaction_change_list.html"
|
change_list_template = "admin/interaction_change_list.html"
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
@ -1308,4 +1332,4 @@ class VoterLikelihoodAdmin(BaseImportAdminMixin, admin.ModelAdmin):
|
|||||||
@admin.register(CampaignSettings)
|
@admin.register(CampaignSettings)
|
||||||
class CampaignSettingsAdmin(admin.ModelAdmin):
|
class CampaignSettingsAdmin(admin.ModelAdmin):
|
||||||
list_display = ('tenant', 'donation_goal')
|
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):
|
def __str__(self):
|
||||||
return self.name
|
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):
|
class Voter(models.Model):
|
||||||
SUPPORT_CHOICES = [
|
SUPPORT_CHOICES = [
|
||||||
('unknown', 'Unknown'),
|
('unknown', 'Unknown'),
|
||||||
@ -240,6 +250,26 @@ class Event(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.event_type} on {self.date}"
|
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):
|
class EventParticipation(models.Model):
|
||||||
PARTICIPATION_TYPE_CHOICES = [
|
PARTICIPATION_TYPE_CHOICES = [
|
||||||
("invited", "Invited"),
|
("invited", "Invited"),
|
||||||
@ -265,6 +295,7 @@ class Donation(models.Model):
|
|||||||
|
|
||||||
class Interaction(models.Model):
|
class Interaction(models.Model):
|
||||||
voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='interactions')
|
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)
|
type = models.ForeignKey(InteractionType, on_delete=models.SET_NULL, null=True)
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
description = models.CharField(max_length=255)
|
description = models.CharField(max_length=255)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user