python - 是否可以在后端为表单设置 enctype="multipart/form-data" ?
问题描述
我正在使用 Django 框架开发票务系统。我想实现一个功能,可以通过电子邮件创建票证,到目前为止收件人电子邮件与用户相关联。
我使用 mailgun 创建了一个将邮件数据重定向到 URL 的路由。
除了附件之外,我已经能够成功处理邮件内容,我认为这是因为我没有设置上传文件时必需的 enctype 属性。表单未验证。
是否可以在银行设置 enctype="multipart/form-data" ?
模型.py
from django.db import models
from .utils import *
from django.db.models.signals import pre_save
class Ticket(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
subject = models.CharField(max_length=50, blank=False, null=False)
message = models.TextField()
task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True, blank=True)
status = models.CharField(max_length=50, choices=STATUS_CHOICES, default='open')
request_time = models.DateTimeField(auto_now_add=True)
response_time = models.DateTimeField(auto_now=True)
priority = models.CharField(max_length=50, choices=PRIORITY_CHOICES, default='mid')
is_active = models.BooleanField(_('active'), default=True)
objects = GeneralManager()
def __str__(self):
return self.subject
def get_absolute_url(self):
return reverse('ticket_detail', kwargs={'pk': self.pk})
def req_ticket_create_update_receiver(sender, instance, *args, **kwargs):
# reciever function for ticket model
from_email = config('from_email')
if Ticket.objects.filter(id=instance.id).exists():
if instance.status == 'close':
subject = f'Ticket With ID {instance.id} Has Been Closed'
message = f'Hello {instance.user.get_short_name()}, \nYour ticket with ID {instance.id} has been closed. We hope the resolution to this trouble was up to satisfaction. \n\nRegards.'
instance.user.email_user(subject=subject, message=message, from_email=from_email, fail_silently=True,)
elif instance.status == 'pending':
subject = f'Work Has Begun On Your Ticket With ID {instance.id}'
message = f'Hello {instance.user.get_short_name()}, \nWe\'ve started working on your ticket with ID {instance.id}. \n\nRegards.'
instance.user.email_user(subject=subject, message=message, from_email=from_email, fail_silently=True,)
else:
subject = f'Ticket With ID {instance.id} Has Been Issued'
message = f'Hello {instance.user.get_short_name()}, \nYour ticket with ID {instance.id} has been created. We have started working on it & you\'ll get a feedback as soon as possible. \n\nRegards.'
instance.user.email_user(subject=subject, message=message, from_email=from_email, fail_silently=True,)
pre_save.connect(req_ticket_create_update_receiver, sender=Ticket, weak=False)
class Attachment(models.Model):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
file = models.FileField(upload_to=upload_image_path, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
实用程序.py
import os
import random
def get_filename_ext(filepath):
"""Split file path into name & extension"""
base_name = os.path.basename(filepath)
name, ext = os.path.splitext(base_name)
return name, ext
def upload_image_path(instance, filename):
"""Create New File Name"""
new_filename = random.randint(1, 3910209312)
name, ext = get_filename_ext(filename)
final_filename = f"{new_filename}{ext}"
return f'tickets/{new_filename}/{final_filename}'
表格.py
from .models import Attachment
class AttachmentForm(ModelForm):
class Meta:
model = Attachment
fields = ['ticket', 'file']
项目 urls.py
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
from django.views.generic import TemplateView
urlpatterns = [
path('', include('Ticket.urls')),
path('', include('Auth.urls')),
path('', TemplateView.as_view(template_name='dashboard.html'), name='home'),
path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
应用程序 urls.py
from django.contrib.auth import views as auth_views
from django.urls import path
from .views import *
urlpatterns = [
path('consume/email/', recieve_incoming_mail, name='consume-email'),
path('tickets/<int:pk>/del/', ticket_del_view, name='ticket_delete'),
path('tickets/search/', SearchView.as_view(), name='ticket_search'),
path('tickets/create/', TicketCreateView.as_view(), name='ticket_create'),
path('tickets/<int:pk>/edit/', TicketUpdateView.as_view(), name='ticket_update'),
path('tickets/<int:pk>/', TicketDetailView.as_view(), name='ticket_detail'),
path('tickets/', TicketListView.as_view(), name='ticket_list'),
path('company/<int:pk>/del/', company_del_view, name='company_delete'),
path('company/create/', CompanyCreateView.as_view(), name='company_create'),
path('company/<int:pk>/edit/', CompanyUpdateView.as_view(), name='company_update'),
path('company/<int:pk>/', CompanyDetailView.as_view(), name='company_detail'),
path('company/', CompanyListView.as_view(), name='company_list'),
path('projects/<int:pk>/del/', project_del_view, name='project_delete'),
path('projects/create/', ProjectCreateView.as_view(), name='project_create'),
path('projects/<int:pk>/edit/', ProjectUpdateView.as_view(), name='project_update'),
path('projects/<int:pk>/', ProjectDetailView.as_view(), name='project_detail'),
path('projects/', ProjectListView.as_view(), name='project_list'),
path('tasks/<int:pk>/del/', task_del_view, name='task_delete'),
path('tasks/create/', TaskCreateView.as_view(), name='task_create'),
path('tasks/<int:pk>/edit/', TaskUpdateView.as_view(), name='task_update'),
path('tasks/<int:pk>/', TaskDetailView.as_view(), name='task_detail'),
path('tasks/', TaskListView.as_view(), name='task_list'),
]
视图.py
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.http import QueryDict
@csrf_exempt
def recieve_incoming_mail(request):
'''
Consumes incoming mail
Creates a new ticket if sender is user.
'''
if request.method == 'POST':
# reference mime
print(request.POST, request.FILES)
subject = request.POST.get('subject', '')
body_plain = request.POST.get('body-plain', '')
sender = request.POST.get('sender', '')
# check if user exist before issuing ticket from incoming email
if User.objects.filter(email=sender).active().exists():
user = User.objects.get(email=sender)
ticket = Ticket.objects.create(user=user, subject=subject,
message=body_plain
)
if ticket and request.FILES:
print('About to start saving files!!!')
dict={'ticket':ticket}
data = QueryDict('', mutable=True)
data.update(dict)
print(data)
form = AttachmentForm(data=data, files=request.FILES)
if form.is_valid():
print('Saving file!!!')
form.save()
print('Incoming Email Consumed!!!!!')
else:
# send email to sender to create an Account
subject = 'Create an account'
message = 'Hello,\nYou tried to create a ticket for resolution but your email doesnt exist in our database.\nCreate an account via the link below & resend the mail.\nhttps://tcsys.herokuapp.com/user/create/\nRegards'
send_mail(subject=subject, message=message,
from_email= config('from_email'),
recipient_list=[from_email])
# Mailgun needs a 2** http response to know the process was successful
# unless mg will resend in 5mins
return HttpResponse('OK')
解决方案
- pathlib.Path 很棒!
实用程序.py
import random
from pathlib import Path
def get_filename_ext(filepath):
"""Split file path into name & extension"""
p = Path(filepath)
name, ext = p.stem, p.suffix
return name, ext
def upload_image_path(instance, filename):
"""Create New File Name"""
new_filename = random.randint(1, 3910209312)
final_filename = f"{new_filename}{Path(filename).suffix}"
return f'tickets/{new_filename}/{final_filename}'
- 在后端设置 html 内容的示例
post.html
<form method="post">{% csrf_token %}
{{ form.as_p }}
</form>
视图.py
import re
from pathlib import Path
from django.http import HttpResonse
from django.template import loader
from django.template import Template
from django.template import Context
def view1(request):
form_class = PostForm
if request.method == 'POST':
form = form_class(request.POST, request.FILES)
form.save()
return redirect('/')
else:
form = form_class()
template = loader.get_template('post.html')
html = Path(str(template.origin)).read_text()
patt = re.compile(r'(<form )(.*?)>')
t = 'enctype="multipart/form-data"'
if (m := patt.search(html)) and t not in m.group(2): # python3.8 syntax
html = patt.sub(rf'\1\2 {t}>', html)
template = Template(html)
return HttpResponse(template.render(Context({'form': form})))