Autosave: 20260124-155519
This commit is contained in:
parent
aade4cc131
commit
e2ad03e446
151
ERD.md
Normal file
151
ERD.md
Normal file
@ -0,0 +1,151 @@
|
||||
# Entity Relationship Diagram
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
Tenant ||--o{ TenantUserRole : has
|
||||
Tenant ||--o{ InteractionType : defines
|
||||
Tenant ||--o{ DonationMethod : defines
|
||||
Tenant ||--o{ ElectionType : defines
|
||||
Tenant ||--o{ EventType : defines
|
||||
Tenant ||--o{ ParticipationType : defines
|
||||
Tenant ||--o{ Voter : belongs_to
|
||||
Tenant ||--o{ Event : organizes
|
||||
|
||||
User ||--o{ TenantUserRole : assigned_to
|
||||
|
||||
Voter ||--o{ VotingRecord : has
|
||||
Voter ||--o{ EventParticipation : participates
|
||||
Voter ||--o{ Donation : makes
|
||||
Voter ||--o{ Interaction : receives
|
||||
Voter ||--o{ VoterLikelihood : has
|
||||
|
||||
Event ||--o{ EventParticipation : includes
|
||||
EventType ||--o{ Event : categorizes
|
||||
|
||||
InteractionType ||--o{ Interaction : categorizes
|
||||
DonationMethod ||--o{ Donation : categorizes
|
||||
ElectionType ||--o{ VoterLikelihood : categorizes
|
||||
ParticipationType ||--o{ EventParticipation : categorizes
|
||||
|
||||
Tenant {
|
||||
int id PK
|
||||
string name
|
||||
string slug
|
||||
text description
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
User {
|
||||
int id PK
|
||||
string username
|
||||
string email
|
||||
string first_name
|
||||
string last_name
|
||||
}
|
||||
|
||||
TenantUserRole {
|
||||
int id PK
|
||||
int user_id FK
|
||||
int tenant_id FK
|
||||
string role
|
||||
}
|
||||
|
||||
InteractionType {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string name
|
||||
boolean is_active
|
||||
}
|
||||
|
||||
DonationMethod {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string name
|
||||
boolean is_active
|
||||
}
|
||||
|
||||
ElectionType {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string name
|
||||
boolean is_active
|
||||
}
|
||||
|
||||
EventType {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string name
|
||||
boolean is_active
|
||||
}
|
||||
|
||||
ParticipationType {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string name
|
||||
boolean is_active
|
||||
}
|
||||
|
||||
Voter {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
string voter_id
|
||||
string first_name
|
||||
string last_name
|
||||
text address
|
||||
string phone
|
||||
string email
|
||||
string district
|
||||
string precinct
|
||||
date registration_date
|
||||
string candidate_support
|
||||
string yard_sign
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
VotingRecord {
|
||||
int id PK
|
||||
int voter_id FK
|
||||
date election_date
|
||||
string election_description
|
||||
string primary_party
|
||||
}
|
||||
|
||||
Event {
|
||||
int id PK
|
||||
int tenant_id FK
|
||||
date date
|
||||
int event_type_id FK
|
||||
text description
|
||||
}
|
||||
|
||||
EventParticipation {
|
||||
int id PK
|
||||
int event_id FK
|
||||
int voter_id FK
|
||||
int participation_type_id FK
|
||||
}
|
||||
|
||||
Donation {
|
||||
int id PK
|
||||
int voter_id FK
|
||||
date date
|
||||
int method_id FK
|
||||
decimal amount
|
||||
}
|
||||
|
||||
Interaction {
|
||||
int id PK
|
||||
int voter_id FK
|
||||
int type_id FK
|
||||
date date
|
||||
string description
|
||||
text notes
|
||||
}
|
||||
|
||||
VoterLikelihood {
|
||||
int id PK
|
||||
int voter_id FK
|
||||
int election_type_id FK
|
||||
string likelihood
|
||||
}
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
@ -1,7 +1,8 @@
|
||||
from django.contrib import admin
|
||||
from .models import (
|
||||
Tenant, TenantUserRole, InteractionType, DonationMethod, ElectionType, EventType, Voter,
|
||||
VotingRecord, Event, EventParticipation, Donation, Interaction, VoterLikelihood
|
||||
Tenant, TenantUserRole, InteractionType, DonationMethod, ElectionType, EventType,
|
||||
ParticipationType, Voter, VotingRecord, Event, EventParticipation, Donation,
|
||||
Interaction, VoterLikelihood
|
||||
)
|
||||
|
||||
class TenantUserRoleInline(admin.TabularInline):
|
||||
@ -44,6 +45,12 @@ class EventTypeAdmin(admin.ModelAdmin):
|
||||
list_filter = ('tenant', 'is_active')
|
||||
search_fields = ('name',)
|
||||
|
||||
@admin.register(ParticipationType)
|
||||
class ParticipationTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'tenant', 'is_active')
|
||||
list_filter = ('tenant', 'is_active')
|
||||
search_fields = ('name',)
|
||||
|
||||
class VotingRecordInline(admin.TabularInline):
|
||||
model = VotingRecord
|
||||
extra = 1
|
||||
@ -74,5 +81,5 @@ class EventAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(EventParticipation)
|
||||
class EventParticipationAdmin(admin.ModelAdmin):
|
||||
list_display = ('voter', 'event')
|
||||
list_filter = ('event__tenant', 'event')
|
||||
list_display = ('voter', 'event', 'participation_type')
|
||||
list_filter = ('event__tenant', 'event', 'participation_type')
|
||||
31
core/migrations/0005_participationtype_and_more.py
Normal file
31
core/migrations/0005_participationtype_and_more.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-24 15:43
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_remove_voter_geocode_donationmethod_is_active_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ParticipationType',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('tenant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participation_types', to='core.tenant')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('tenant', 'name')},
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventparticipation',
|
||||
name='participation_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.participationtype'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -41,7 +41,7 @@ class InteractionType(models.Model):
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.tenant.name})"
|
||||
return self.name
|
||||
|
||||
class DonationMethod(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='donation_methods')
|
||||
@ -52,7 +52,7 @@ class DonationMethod(models.Model):
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.tenant.name})"
|
||||
return self.name
|
||||
|
||||
class ElectionType(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='election_types')
|
||||
@ -63,7 +63,7 @@ class ElectionType(models.Model):
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.tenant.name})"
|
||||
return self.name
|
||||
|
||||
class EventType(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='event_types')
|
||||
@ -74,7 +74,18 @@ class EventType(models.Model):
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.tenant.name})"
|
||||
return self.name
|
||||
|
||||
class ParticipationType(models.Model):
|
||||
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='participation_types')
|
||||
name = models.CharField(max_length=100)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('tenant', 'name')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Voter(models.Model):
|
||||
SUPPORT_CHOICES = [
|
||||
@ -127,6 +138,7 @@ class Event(models.Model):
|
||||
class EventParticipation(models.Model):
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='participations')
|
||||
voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='event_participations')
|
||||
participation_type = models.ForeignKey(ParticipationType, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.voter} at {self.event}"
|
||||
@ -164,4 +176,4 @@ class VoterLikelihood(models.Model):
|
||||
unique_together = ('voter', 'election_type')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.voter} - {self.election_type}: {self.get_likelihood_display()}"
|
||||
return f"{self.voter} - {self.election_type}: {self.get_likelihood_display()}"
|
||||
Loading…
x
Reference in New Issue
Block a user