feat: add Organization model with tree structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
TianyangZhang 2026-03-24 17:34:56 +08:00
parent c3466f4866
commit 7e089bd5ec
8 changed files with 118 additions and 5 deletions

View File

@ -0,0 +1,32 @@
# Generated by Django 4.2.20 on 2026-03-24 09:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Organization',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='公司名称')),
('logo', models.ImageField(blank=True, null=True, upload_to='org_logos/')),
('description', models.TextField(blank=True, verbose_name='公司简介')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='联系邮箱')),
('is_active', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='organizations.organization', verbose_name='上级公司')),
],
options={
'verbose_name': '组织架构',
'verbose_name_plural': '组织架构',
},
),
]

View File

@ -2,12 +2,23 @@ from django.db import models
class Organization(models.Model):
name = models.CharField(max_length=255)
name = models.CharField(max_length=100, verbose_name='公司名称')
parent = models.ForeignKey(
'self', null=True, blank=True,
on_delete=models.SET_NULL,
related_name='children',
verbose_name='上级公司'
)
logo = models.ImageField(upload_to='org_logos/', null=True, blank=True)
description = models.TextField(blank=True, verbose_name='公司简介')
email = models.EmailField(blank=True, verbose_name='联系邮箱')
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
app_label = 'organizations'
verbose_name = '组织'
verbose_name_plural = '组织'
verbose_name = '组织架构'
verbose_name_plural = '组织架构'
def __str__(self):
return self.name

View File

@ -0,0 +1,22 @@
from rest_framework import serializers
from .models import Organization
class OrganizationSerializer(serializers.ModelSerializer):
class Meta:
model = Organization
fields = ['id', 'name', 'parent', 'logo', 'description', 'email', 'is_active']
class OrganizationTreeSerializer(serializers.ModelSerializer):
"""带子公司列表,用于门户展示"""
children = serializers.SerializerMethodField()
class Meta:
model = Organization
fields = ['id', 'name', 'logo', 'description', 'email', 'children']
def get_children(self, obj):
return OrganizationSerializer(
obj.children.filter(is_active=True), many=True
).data

View File

@ -0,0 +1,23 @@
import pytest
from apps.organizations.models import Organization
@pytest.mark.django_db
class TestOrganizationModel:
def test_create_group(self):
org = Organization.objects.create(name='示例集团', email='group@example.com')
assert org.parent is None
assert org.is_active is True
def test_create_subsidiary(self):
parent = Organization.objects.create(name='示例集团', email='group@example.com')
child = Organization.objects.create(
name='子公司A', email='a@example.com', parent=parent
)
assert child.parent == parent
def test_list_subsidiaries(self):
parent = Organization.objects.create(name='集团', email='g@example.com')
Organization.objects.create(name='子A', email='a@example.com', parent=parent)
Organization.objects.create(name='子B', email='b@example.com', parent=parent)
assert parent.children.count() == 2

View File

@ -1,3 +1,9 @@
from django.urls import path
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import OrganizationPublicViewSet, OrganizationManageViewSet
urlpatterns = []
router = DefaultRouter()
router.register('public', OrganizationPublicViewSet, basename='org-public')
router.register('manage', OrganizationManageViewSet, basename='org-manage')
urlpatterns = [path('', include(router.urls))]

View File

@ -0,0 +1,19 @@
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
from .models import Organization
from .serializers import OrganizationSerializer, OrganizationTreeSerializer
from apps.accounts.permissions import IsSuperAdmin
class OrganizationPublicViewSet(viewsets.ReadOnlyModelViewSet):
"""公开只读:门户展示用"""
queryset = Organization.objects.filter(is_active=True, parent__isnull=False)
serializer_class = OrganizationSerializer
permission_classes = [AllowAny]
class OrganizationManageViewSet(viewsets.ModelViewSet):
"""超管:完整增删改查"""
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
permission_classes = [IsSuperAdmin]