如何允许django最终用户以受控和安全的方式创建自己的表?

如何允许django最终用户以受控和安全的方式创建自己的表?,django,python-3.x,django-models,Django,Python 3.x,Django Models,这是关于:Django/Django-ORM/POSTGRES 目标: 允许最终用户从现有模型继承、在其中创建额外字段或创建全新模型 伪模型代码 示例: 原始模型 name = "Main Model" Value_1 = "First Value" 用户创建的变体 parent = OriginalModel name = "Custom Model" Value_1 = "First Value" Value_2 = "Custom Additional Value" 我试过: test

这是关于:Django/Django-ORM/POSTGRES

目标: 允许最终用户从现有模型继承、在其中创建额外字段或创建全新模型

伪模型代码 示例:

原始模型

name = "Main Model"
Value_1 = "First Value"
用户创建的变体

parent = OriginalModel
name = "Custom Model"
Value_1 = "First Value"
Value_2 = "Custom Additional Value"
我试过:

test_choices = (
    ('str', 'str'),
    ('num', 'num'),
)


class App(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='users')
    name = models.CharField(max_length=100)


class AppField(models.Model):
    app = models.ForeignKey(App, on_delete=models.CASCADE)
    type = models.CharField(max_length=100, choices=test_choices, null=True)
    title = models.CharField(max_length=100, default='')
问题 如何允许用户创建将AppField中的字段用作模型字段的AppItem


你知道做这件事的更好方法吗?

以下是我如何开始使用JSONField(和PostgreSQL)来应对这一挑战。这只是给你一个基本的想法,我试着遵循Django的原则。前两个简单的模型。一个用于存储用户定义的模型定义,另一个用于存储数据

models.py

from django.db import models
from django.contrib.postgres.fields import JSONField
from django.utils.text import slugify

class ModelDefinition(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    verbose_name = models.CharField(max_length=50)
    name = models.CharField(max_length=50, unique=True)
    definition = JSONField()

    def save(self, *args, **kwargs):
        self.name = slugify(self.verbose_name)
        super().save(*args, **kwargs)

class Data(models.Model):
    model_definition = models.ForeignKey(ModelDefinition, on_delete=models.CASCADE)
    data = JSONField()
from .models import ModelDefinition, Data
from django.http import HttpResponse, JsonResponse

def create_model_definition(request):
    ''' Handles creation of model definitions '''

    model_definition = {
        'fields': [
            {
                'name': 'automobile',
                'verbose_name': 'Automobile',
                'data_type': 'string',
                'max_length': 50,
                'blank': False,
                'null': False
            },
            {
                'name': 'type',
                'verbose_name': 'Automobile type',
                'data_type': 'string',
                'max_length': 20,
                'blank': False,
                'null': False            
            },
            {
                'name': 'doors',
                'verbose_name': 'Number of doors',
                'data_type': 'integer',
                'blank': False,
                'null': False
            }
        ],
        'global_options': {
            'guest': {
                'verbose_name': 'Allow guests to enter data',
                'option': True
            },
            'public': {
                'verbose_name': 'Data is publicly accessible',
                'option': False
            }
        }

    }

    ModelDefinition.objects.create(
        user=request.user,
        verbose_name='My automobiles',
        definition=model_definition
    )

    return HttpResponse('model definition created')

def add_data(request, table='my-automobiles'):
    ''' Handles data entry  '''

    model_definition = get_object_or_404(ModelDefinition, user=request.user, name=table)
    if not request.user.is_authenticated and not model_definition.definition['global_options']['guest']['option']:
         return HttpResponse('Sorry, only authenticated users can enter data')

    data_rows = [
        {
            'automobile': 'Audi',
            'type': 'limousine',
            'doors': 4
        },
        {
            'automobile': 'Fiat',
            'type': 'hatchback',
            'doors': 3
        },
        {
            'automobile': 'Iveco',
            'type': 'truck',
            'doors': 2
        }      
    ]

    for row in data_rows:
        Data.objects.create(
            model_definition=model_definition,
            data=data
        )

    return HttpResponse('rows saved')

def show_data(request, table='my-automobiles'):
    ''' Returns data in JSON format '''

    model_definition = get_object_or_404(ModelDefinition, name=table)
    if not request.user.is_authenticated and not model_definition.definition['global_options']['public']['option']:
         return HttpResponse('Sorry, only authenticated users can view data')

    data = Data.objects.filter(model_definition__name=table)            
    return JsonResponse(data)
下面是一个如何添加模型定义、添加和返回数据的示例。我没有包括数据验证,因为编写基本验证代码至少需要一个小时

views.py

from django.db import models
from django.contrib.postgres.fields import JSONField
from django.utils.text import slugify

class ModelDefinition(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    verbose_name = models.CharField(max_length=50)
    name = models.CharField(max_length=50, unique=True)
    definition = JSONField()

    def save(self, *args, **kwargs):
        self.name = slugify(self.verbose_name)
        super().save(*args, **kwargs)

class Data(models.Model):
    model_definition = models.ForeignKey(ModelDefinition, on_delete=models.CASCADE)
    data = JSONField()
from .models import ModelDefinition, Data
from django.http import HttpResponse, JsonResponse

def create_model_definition(request):
    ''' Handles creation of model definitions '''

    model_definition = {
        'fields': [
            {
                'name': 'automobile',
                'verbose_name': 'Automobile',
                'data_type': 'string',
                'max_length': 50,
                'blank': False,
                'null': False
            },
            {
                'name': 'type',
                'verbose_name': 'Automobile type',
                'data_type': 'string',
                'max_length': 20,
                'blank': False,
                'null': False            
            },
            {
                'name': 'doors',
                'verbose_name': 'Number of doors',
                'data_type': 'integer',
                'blank': False,
                'null': False
            }
        ],
        'global_options': {
            'guest': {
                'verbose_name': 'Allow guests to enter data',
                'option': True
            },
            'public': {
                'verbose_name': 'Data is publicly accessible',
                'option': False
            }
        }

    }

    ModelDefinition.objects.create(
        user=request.user,
        verbose_name='My automobiles',
        definition=model_definition
    )

    return HttpResponse('model definition created')

def add_data(request, table='my-automobiles'):
    ''' Handles data entry  '''

    model_definition = get_object_or_404(ModelDefinition, user=request.user, name=table)
    if not request.user.is_authenticated and not model_definition.definition['global_options']['guest']['option']:
         return HttpResponse('Sorry, only authenticated users can enter data')

    data_rows = [
        {
            'automobile': 'Audi',
            'type': 'limousine',
            'doors': 4
        },
        {
            'automobile': 'Fiat',
            'type': 'hatchback',
            'doors': 3
        },
        {
            'automobile': 'Iveco',
            'type': 'truck',
            'doors': 2
        }      
    ]

    for row in data_rows:
        Data.objects.create(
            model_definition=model_definition,
            data=data
        )

    return HttpResponse('rows saved')

def show_data(request, table='my-automobiles'):
    ''' Returns data in JSON format '''

    model_definition = get_object_or_404(ModelDefinition, name=table)
    if not request.user.is_authenticated and not model_definition.definition['global_options']['public']['option']:
         return HttpResponse('Sorry, only authenticated users can view data')

    data = Data.objects.filter(model_definition__name=table)            
    return JsonResponse(data)

好吧,我就是这样开始工作的,不知道我会得到什么。当然,我还没有测试过这些代码:)

澄清说明:我们为什么要这样做?在应用程序[Podio]中可以找到此功能的一个很好的用途,它允许您创建和自定义自己的待办事项列表应用程序[],然后最终用户只需填写如下字段即可添加一个应用程序项目:[]想象一堆电子表格,一个独特的电子表格是一个应用程序,每一列是一个AppField,每一行都在AppItem中我很确定podio.com使用JSON来形成“用户表”(请参阅)或者具有类似功能的东西。允许用户破坏基本数据库结构是不明智的。您最终会发现一个数据库完全是一堆乱七八糟的表,其中大多数表可能已过时/未被使用。谢谢!我想这会行得通的。我要试试这个[];并将每一行存储在TestAppData表中,以便两个用户可以同时编辑两个不同的应用程序行,而无需相互重写,但我们必须在每个TestAppData项上声明列。不要在JSONField上过早放弃:)这是需要动态结构的完美选择。大致上是这样做的?@Sam,是的。来自JSON的数据字段在Django中转换为字典。