我应该如何使用 Django 中的电子签名 Web 应用程序的邀请和收件人构建我的数据库实体?
How should I structure my database entities with invites and recipients for e-signing web app in Django?
我有兴趣为我的电子签名网络应用程序实现以下要求。
- 用户可以创建新的签约合同。该合同可以包括多个用户签署。合约创建者需要提供收件人的电子邮件。每个收件人都会分配额外的数据,例如签名详细信息、说明等。
- 但是,受邀用户仍然可以不在系统中。这是最棘手的部分。
现在我的以下实现如下:
- 我创建了一个合同,然后通过电子邮件筛选来检查用户是否存在于系统中。如果用户存在,我创建一个 多对多实体 ContractRecipientEvent 使用 through intermediate table 附加data,分配给合约。我创建它是多对多的,因为同一个用户可以分配给多个合同。
- 如果用户不在,我创建邀请模型,设置所有收件人的特定数据,然后发送电子邮件。然后用户注册,我 运行 查询 带有该电子邮件 的所有邀请记录并通过 复制 数据创建 ContractRecipientEvent邀请模式。
我不喜欢我的方法有以下几点:
- 多对多字段。我只想为我的合同接收者使用纯外键,但我不确定我应该如何将多个用户分配给同一个合同?也许我应该创建一个新的模型 ContractRecipient,将用户和合同作为外键,但这也是一个多对多字段?
- 我不喜欢我需要将数据从 Invitation 模型复制到 ContractRecipientEvent 并且只在用户注册后创建 ContractRecipientEvent,因为我需要一个用户实体来创建一个 ContractRecipientEvent,它有一个用户的外键。
- 权限结构难以管理。我需要检查合同数据库记录中包含的所有用户,并检查他们是否已分配给 合同 ID,他们用于签署 POST 请求 .
我附上合同清单的最终 JSON 代码。它有效,但我想要一个正确的模型结构:
{
"results": [
{
"id": 178,
"is_author": true,
"title": "ahhzhzh",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN",
"email": "test2331@gmail.com"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE",
"email": "test2333@gmail.com"
}
]
},
{
"id": 179,
"is_author": true,
"title": "dhhdhd",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN",
"email": "test123@gmail.com"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE",
"email": "test233@gmail.com"
}
]
},
]
}
M2M 和两个 ForeignKeys 之间的唯一区别是通过 table 但让我们看看我是否理解。如果我们从以下模型开始会怎样:
class User(models.Model):
email = models.CharField(...)
...
class Contract(models.Model):
user = models.ForeignKey('User', ..., related_name='contracts')
...
class Signature(models.Model):
user = models.ForeignKey('User', ..., related_name='signatures')
contract = models.ForeignKey('User', ..., related_name='signatures')
is_signed = models.BooleanField(default=False)
...
class Event(models.Model):
user = models.ForeignKey('User', ..., related_name='events')
contract = models.ForeignKey('Contract', ..., related_name='events')
signature = models.ForeignKey('Signature', ..., related_name='events')
message = models.CharField(...)
...
现在我们可以做如下事情:
# get a specific user:
user = User.objects.get(email=<email>)
# get all of the contracts they own:
users_contracts = user.contracts.all() # OR
users_contracts = Contract.objects.filter(user=user)
# get a specific contract:
contract = Contract.objects.get(id=<contract-id>)
# get all the signatures on a contract:
signatures_on_contract = contract.signatures.all() # OR
signatures_on_contract = Signature.objects.filter(contract=contract)
# get all the signatures for a user:
users_signatures = user.signatures.all()
# get all the contracts that the user signed:
users_signed_contracts = Contracts.objects.filter(
signatures__in = users_signatures,
signatures__is_signed = True
)
# get all the events on the contract:
events = contract.events.order_by('id')
现在我们的合同 json 可以看起来像:
// i.e.: contract with id 7:
{
'id' : 7,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'signatures' : [
{
'id' : 3,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'is_signed' : true
},
{
'user' : {
'id' : 4,
'email' : 'other@email.com'
},
'is_signed' : false
}
],
'events' : [
{
'id' : 6,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'contract' : {
'id' : 7
},
'signature' : {
'id' : 3
},
'message' : 'signed contract 7'
}
]
}
此处的 Event
模型可能过于合格,不需要它拥有的所有 ForeignKey
关系,但这样您可以灵活地创建您的 json.
编辑
处理需要签约的用户:
# a list of emails:
emails = ['email@1.com', 'email@2.com', ...]
for email in emails:
# get or create a user:
user, created = User.objects.get_or_create(email=email)
# new user logic:
if created:
# set temp password
# redirect users to change password page before signing a doc (can be done elsewhere)
...
# existing user logic:
else:
...
# create signatures for each user, and add them to the contract:
signature = Signature.objects.create(user=user, contract=contract)
...
编辑 2
这是一个使用 DRF 基于对象限制对 Signature
table 的请求的示例:
views.py
class SignatureViewSet(viewsets.ModelViewSet):
# override this method to limit access:
def get_queryset(self):
# superusers can access all items:
if self.request.user.is_superuser:
return self.queryset
# otherwise, users can only access their own signatures:
else:
return self.queryset.filter(user=self.request.user)
我有兴趣为我的电子签名网络应用程序实现以下要求。
- 用户可以创建新的签约合同。该合同可以包括多个用户签署。合约创建者需要提供收件人的电子邮件。每个收件人都会分配额外的数据,例如签名详细信息、说明等。
- 但是,受邀用户仍然可以不在系统中。这是最棘手的部分。
现在我的以下实现如下:
- 我创建了一个合同,然后通过电子邮件筛选来检查用户是否存在于系统中。如果用户存在,我创建一个 多对多实体 ContractRecipientEvent 使用 through intermediate table 附加data,分配给合约。我创建它是多对多的,因为同一个用户可以分配给多个合同。
- 如果用户不在,我创建邀请模型,设置所有收件人的特定数据,然后发送电子邮件。然后用户注册,我 运行 查询 带有该电子邮件 的所有邀请记录并通过 复制 数据创建 ContractRecipientEvent邀请模式。
我不喜欢我的方法有以下几点:
- 多对多字段。我只想为我的合同接收者使用纯外键,但我不确定我应该如何将多个用户分配给同一个合同?也许我应该创建一个新的模型 ContractRecipient,将用户和合同作为外键,但这也是一个多对多字段?
- 我不喜欢我需要将数据从 Invitation 模型复制到 ContractRecipientEvent 并且只在用户注册后创建 ContractRecipientEvent,因为我需要一个用户实体来创建一个 ContractRecipientEvent,它有一个用户的外键。
- 权限结构难以管理。我需要检查合同数据库记录中包含的所有用户,并检查他们是否已分配给 合同 ID,他们用于签署 POST 请求 .
我附上合同清单的最终 JSON 代码。它有效,但我想要一个正确的模型结构:
{
"results": [
{
"id": 178,
"is_author": true,
"title": "ahhzhzh",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN",
"email": "test2331@gmail.com"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE",
"email": "test2333@gmail.com"
}
]
},
{
"id": 179,
"is_author": true,
"title": "dhhdhd",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN",
"email": "test123@gmail.com"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE",
"email": "test233@gmail.com"
}
]
},
]
}
M2M 和两个 ForeignKeys 之间的唯一区别是通过 table 但让我们看看我是否理解。如果我们从以下模型开始会怎样:
class User(models.Model):
email = models.CharField(...)
...
class Contract(models.Model):
user = models.ForeignKey('User', ..., related_name='contracts')
...
class Signature(models.Model):
user = models.ForeignKey('User', ..., related_name='signatures')
contract = models.ForeignKey('User', ..., related_name='signatures')
is_signed = models.BooleanField(default=False)
...
class Event(models.Model):
user = models.ForeignKey('User', ..., related_name='events')
contract = models.ForeignKey('Contract', ..., related_name='events')
signature = models.ForeignKey('Signature', ..., related_name='events')
message = models.CharField(...)
...
现在我们可以做如下事情:
# get a specific user:
user = User.objects.get(email=<email>)
# get all of the contracts they own:
users_contracts = user.contracts.all() # OR
users_contracts = Contract.objects.filter(user=user)
# get a specific contract:
contract = Contract.objects.get(id=<contract-id>)
# get all the signatures on a contract:
signatures_on_contract = contract.signatures.all() # OR
signatures_on_contract = Signature.objects.filter(contract=contract)
# get all the signatures for a user:
users_signatures = user.signatures.all()
# get all the contracts that the user signed:
users_signed_contracts = Contracts.objects.filter(
signatures__in = users_signatures,
signatures__is_signed = True
)
# get all the events on the contract:
events = contract.events.order_by('id')
现在我们的合同 json 可以看起来像:
// i.e.: contract with id 7:
{
'id' : 7,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'signatures' : [
{
'id' : 3,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'is_signed' : true
},
{
'user' : {
'id' : 4,
'email' : 'other@email.com'
},
'is_signed' : false
}
],
'events' : [
{
'id' : 6,
'user' : {
'id' : 2,
'email' : 'some@email.com'
},
'contract' : {
'id' : 7
},
'signature' : {
'id' : 3
},
'message' : 'signed contract 7'
}
]
}
此处的 Event
模型可能过于合格,不需要它拥有的所有 ForeignKey
关系,但这样您可以灵活地创建您的 json.
编辑
处理需要签约的用户:
# a list of emails:
emails = ['email@1.com', 'email@2.com', ...]
for email in emails:
# get or create a user:
user, created = User.objects.get_or_create(email=email)
# new user logic:
if created:
# set temp password
# redirect users to change password page before signing a doc (can be done elsewhere)
...
# existing user logic:
else:
...
# create signatures for each user, and add them to the contract:
signature = Signature.objects.create(user=user, contract=contract)
...
编辑 2
这是一个使用 DRF 基于对象限制对 Signature
table 的请求的示例:
views.py
class SignatureViewSet(viewsets.ModelViewSet):
# override this method to limit access:
def get_queryset(self):
# superusers can access all items:
if self.request.user.is_superuser:
return self.queryset
# otherwise, users can only access their own signatures:
else:
return self.queryset.filter(user=self.request.user)