我的模型的简化视图:
# models.py
class User(models.Model):
first_name = models.CharField()
last_name = models.CharField()
team = models.ForeignKey('Team')
...
class Team(models.Model):
name = models.CharField()
class ToDo(models.Model):
task = models.CharField()
description = models.TextField()
owner = models.ForeignKey('User')
# serializers.py
class ToDoSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
class Meta:
model = ToDo
fields = '__all__'
我要基于以下逻辑创建一个POST端点以添加一个新的ToDo
对象:
ToDo
个项目ToDo
项目ToDo
项目问题:在哪里写这个逻辑
我通过使用Permission类尝试过此操作,但我不知道这是否是执行此操作的最佳位置
# views.py
class ToDoViewSet(viewsets.ModelViewSet):
serializer_class = ToDoSerializer
permission_classes = (CanAddToDo,)
# permissions.py
class CanAddToDo(BasePermission):
def has_permission(self, request, view):
owner_id = request.data.get('owner', None)
# owner_id must be set
if not owner_id:
return False
# User can create items if owner is themselves or someone in their team
if User.objects.get(pk=owner_id).team == request.user.team:
return True
return False
def has_object_permission(self, request, view, obj):
"""
Checks if the user owns the todo to edit
"""
return obj.owner == request.user
令我烦恼的是,我没有使用序列化的数据,而是从请求中获取原始所有者的ID,并在权限对象中进行查询以进行我的验证/许可
其他选择可能是在视图的def perform_create(self, serializer):
函数或序列化程序自身中进行此验证。
答案 0 :(得分:1)
还有另一种看待这个问题的方法;所有者验证
在您的ToDo序列化程序中,您可以为所有者字段编写验证
import java.awt.print.PrinterJob;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaTray;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.woo.htmltopdf.HtmlToPdf;
import io.woo.htmltopdf.HtmlToPdfException;
import io.woo.htmltopdf.HtmlToPdfObject;
import io.woo.htmltopdf.PdfPageSize;
public class PDFServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger myLog = LoggerFactory.getLogger(PDFServlet.class);
private static final String PDF_CONTENT = "application/pdf";
private static final String JSON_CONTENT = "application/json; charset=UTF-8";
private static final String DOWNLOAD_FILE = "attachment;filename=%s.pdf";
private static final String REQUEST_STATUS = "[{\"success\":%s}]";
private static final String ERROR_MSG = "Error with %s request: ";
private Map<String, File> myRenderMap = new HashMap<String, File>();
private File myRenderDir;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ServletContext servletContext = this.getServletContext();
String appRoot = servletContext.getRealPath("/");
myRenderDir = new File(appRoot + "render");
if (myRenderDir.exists())
{
try
{
FileUtils.cleanDirectory(myRenderDir);
}
catch (IOException e)
{
myLog.error("Unable to clean render directory.", e);
}
}
else
{
myRenderDir.mkdirs();
}
myLog.debug("Initialized PDFServlet");
}
// downloads to client (or prints) a pre-rendered pdf
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
try
{
String resourceId = request.getParameter("resourceId");
String printer = request.getParameter("printer");
String tray = request.getParameter("tray");
String duplex = request.getParameter("duplex");
String staple = request.getParameter("staple");
if (resourceId == null || resourceId.equals("*") || resourceId.equals("resources"))
{
myLog.debug("Retrieving resources list for GET request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
response.setContentType(JSON_CONTENT);
response.setStatus(200);
try (PrintWriter out = response.getWriter())
{
out.println(getResources());
}
}
else if (resourceId.equalsIgnoreCase("printers"))
{
myLog.debug("Retrieving printers list for GET request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
response.setContentType(JSON_CONTENT);
response.setStatus(200);
try (PrintWriter out = response.getWriter())
{
out.println(getPrinters());
}
}
else if (myRenderMap.containsKey(resourceId))
{
myLog.debug("Retrieving pdf resource for GET request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
while (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
{
Thread.sleep(100);
}
File file = myRenderMap.get(resourceId);
// print
if (printer != null)
{
myLog.debug("Printing existing resource: " + resourceId);
byte[] document = Files.readAllBytes(file.toPath());
boolean printed = print(document, printer, resourceId, tray, duplex, staple);
response.setContentType(JSON_CONTENT);
response.setStatus(printed ? 200 : 500);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
}
}
// download
else
{
myLog.debug("Downloading existing resource: " + resourceId);
try (InputStream in = FileUtils.openInputStream(file))
{
response.setContentType(PDF_CONTENT);
response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
}
catch (HtmlToPdfException e)
{
myLog.error("HTML to PDF conversion error.", e);
}
}
}
else
{
myLog.debug("Resource does not exist for GET request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
response.setContentType(JSON_CONTENT);
response.setStatus(500);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, "false"));
}
}
}
catch (Exception e)
{
String msg = String.format(ERROR_MSG, "GET")
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
myLog.error(msg, e);
throw new ServletException(msg, e);
}
}
// downloads to client (or prints) a pdf that is created from the body content
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
myLog.debug("Retrieving pdf resource for POST request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
try
{
String resourceId = request.getParameter("resourceId");
String size = request.getParameter("size");
String printer = request.getParameter("printer");
String tray = request.getParameter("tray");
String duplex = request.getParameter("duplex");
String staple = request.getParameter("staple");
if (resourceId == null)
{
resourceId = request.getContextPath().substring(1);
}
// resource is currently being rendered
if (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
{
myLog.debug("Waiting for rendering: " + resourceId);
while (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
{
Thread.sleep(100);
}
}
// resource is not already rendered
if (!myRenderMap.containsKey(resourceId))
{
myLog.debug("Newly rendering resource: " + resourceId);
String[] content = IOUtils.toString(request.getReader()).split("\\|", -1);
HtmlToPdf html = create(content);
html.documentTitle(resourceId);
if (size != null)
{
html.pageSize(PdfPageSize.valueOf(size));
}
else
{
html.pageSize(PdfPageSize.Letter);
}
// print
if (printer != null)
{
myLog.debug("Printing new resource: " + resourceId);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(html.convert(), baos);
byte[] document = baos.toByteArray();
boolean printed = print(document, printer, resourceId, tray, duplex, staple);
response.setContentType(JSON_CONTENT);
response.setStatus(printed ? 200 : 500);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
}
}
// download
else
{
myLog.debug("Downloading new resource: " + resourceId);
try (InputStream in = html.convert())
{
response.setContentType(PDF_CONTENT);
response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
}
catch (HtmlToPdfException e)
{
myLog.error("HTML to PDF conversion error.", e);
}
}
}
// resource is already rendered (use file)
else
{
myLog.debug("Resource already exists: " + resourceId);
File file = myRenderMap.get(resourceId);
// print
if (printer != null)
{
myLog.debug("Printing existing resource: " + resourceId);
byte[] document = Files.readAllBytes(file.toPath());
boolean printed = print(document, printer, resourceId, tray, duplex, staple);
response.setContentType(JSON_CONTENT);
response.setStatus(printed ? 200 : 500);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
}
}
// download
else
{
myLog.debug("Downloading existing resource: " + resourceId);
try (InputStream in = FileUtils.openInputStream(file))
{
response.setContentType(PDF_CONTENT);
response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
}
catch (Exception e)
{
myLog.error("Unable to download existing resource.", e);
}
}
}
}
catch (Exception e)
{
String msg = String.format(ERROR_MSG, "POST")
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
myLog.error(msg, e);
throw new ServletException(msg, e);
}
}
// pre-renders a pdf that is created from the body content
@Override
public void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
myLog.debug("Rendering pdf resource for PUT request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
try
{
String resourceId = request.getParameter("resourceId");
String size = request.getParameter("size");
boolean created = false;
if (resourceId == null)
{
resourceId = request.getContextPath().substring(1);
}
if (!myRenderMap.containsKey(resourceId))
{
myRenderMap.put(resourceId, null);
String filePath = myRenderDir.getAbsolutePath() + "/" + resourceId + ".pdf";
String[] content = IOUtils.toString(request.getReader()).split("\\|", -1);
HtmlToPdf html = create(content);
html.documentTitle(resourceId);
if (size != null)
{
html.pageSize(PdfPageSize.valueOf(size));
}
else
{
html.pageSize(PdfPageSize.Letter);
}
created = html.convert(filePath);
if (created)
{
myRenderMap.put(resourceId, new File(filePath));
}
else
{
myRenderMap.remove(resourceId);
}
}
else
{
while (myRenderMap.get(resourceId) == null && myRenderMap.containsKey(resourceId))
{
Thread.sleep(100);
}
created = myRenderMap.containsKey(resourceId);
}
response.setContentType(JSON_CONTENT);
response.setStatus(created ? 200 : 500);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, String.valueOf(created)));
}
}
catch (Exception e)
{
String msg = String.format(ERROR_MSG, "PUT")
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
myLog.error(msg, e);
throw new ServletException(msg, e);
}
}
// removes pre-rendered pdf from server files
@Override
public void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
myLog.debug("Removing pdf resource for DELETE request: "
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
try
{
String resourceId = request.getParameter("resourceId");
List<String> toRemove = new ArrayList<String>();
long now = Calendar.getInstance().getTimeInMillis();
for (String key : myRenderMap.keySet())
{
myLog.debug("Checking: " + key);
File file = myRenderMap.get(key);
if (file == null)
{
Thread.sleep(10000); // wait 10 seconds to see if it renders
}
if (file == null || // the file doesn't actually exist
now - file.lastModified() > (1000 * 60 * 30) || // delete anything older than 30 minutes
key.equals(resourceId)) // requested to delete
{
toRemove.add(key);
}
}
myLog.debug("Removing: " + Arrays.toString(toRemove.toArray()));
for (String key : toRemove)
{
myRenderMap.get(key).delete();
myRenderMap.remove(key);
}
response.setContentType(JSON_CONTENT);
response.setStatus(200);
try (PrintWriter out = response.getWriter())
{
out.println(String.format(REQUEST_STATUS, "true"));
}
}
catch (Exception e)
{
String msg = String.format(ERROR_MSG, "DELETE")
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
myLog.error(msg, e);
throw new ServletException(msg, e);
}
}
private HtmlToPdf create(String[] content)
{
HtmlToPdf html = HtmlToPdf.create();
for (String document : content)
{
if (document.startsWith("<") && document.endsWith(">"))
{
html.object(HtmlToPdfObject.forHtml(document));
}
else
{
html.object(HtmlToPdfObject.forUrl(document));
}
}
return html;
}
private boolean print(byte[] document, String printerIpAddress, String title, String tray, String duplex, String staple)
{
boolean success = false;
List<byte[]> commands = new ArrayList<byte[]>();
if (title != null)
{
commands.add(("@PJL SET JOBNAME=" + title + "\n").getBytes());
}
if (tray != null)
{
commands.add(("@PJL SET MEDIASOURCE=" + tray + "\n").getBytes());
}
if (staple != null)
{
commands.add(("@PJL SET STAPLEOPTION=ONE\n").getBytes());
}
if (duplex != null)
{
commands.add(("@PJL SET DUPLEX=ON\n").getBytes());
if (duplex.equalsIgnoreCase("short"))
{
commands.add(("@PJL SET BINDING=SHORTEDGE\n").getBytes());
}
else if (duplex.equalsIgnoreCase("long"))
{
commands.add(("@PJL SET BINDING=LONGEDGE\n").getBytes());
}
}
try (Socket socket = new Socket(printerIpAddress, 9100))
{
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.write(27);
out.write("%-12345X@PJL\n".getBytes());
for (byte[] command : commands)
{
out.write(command);
}
out.write("@PJL ENTER LANGUAGE=PDF\n".getBytes());
out.write(document);
out.write(27);
out.write("%-12345X".getBytes());
out.flush();
out.close();
success = true;
}
catch (Exception e)
{
System.out.println(e);
}
return success;
}
private String getResources()
{
List<String> toRemove = new ArrayList<String>();
StringBuilder json = new StringBuilder("[");
long now = Calendar.getInstance().getTimeInMillis();
for (String key : myRenderMap.keySet())
{
File file = myRenderMap.get(key);
if (file != null)
{
if (now - file.lastModified() > (1000 * 60 * 30)) // delete anything older than 30 minutes
{
toRemove.add(key);
}
else
{
json.append("{\"resourceId\":\"");
json.append(key);
json.append("\"},");
}
}
}
if (json.length() > 1)
{
json.setLength(json.length() - 1);
}
json.append("]");
for (String key : toRemove)
{
myRenderMap.get(key).delete();
myRenderMap.remove(key);
}
return json.toString();
}
private String getPrinters()
{
StringBuilder json = new StringBuilder("[");
PrintService[] services = PrinterJob.lookupPrintServices();
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
for (PrintService service : services)
{
json.append("{\"printer\":\"");
json.append(service.getName());
json.append("\",\"trays\":[");
Object o = service.getSupportedAttributeValues(Media.class, flavor, null);
if (o != null && o.getClass().isArray())
{
for (Media media : (Media[]) o)
{
if (media instanceof MediaTray)
{
json.append("\"");
json.append(media.toString());
json.append("\",");
}
}
if (json.charAt(json.length() - 1) == ',')
{
json.setLength(json.length() - 1);
}
}
json.append("]},");
}
if (json.length() > 1)
{
json.setLength(json.length() - 1);
}
json.append("]");
return json.toString();
}
}
这很适合创建。但是,要进行更新或删除,您需要检查todo对象上的当前所有者。可以在权限类中完成。您可以使用请求网址中的class ToDoSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
class Meta:
model = ToDo
fields = '__all__'
def validate_owner(self, val):
owner = val
request = self.context.get('request', None)
# it is possible you are using serializer outside an api view
# in which case reqeust will not be present in the serializer context
if request:
if owner.team != request.user.team:
raise serializers.ValidationError('you can only create todos for'
'yourself or your team members')
return val
来获取权限类中的todo对象。