如何使用 Rest 框架 Django 插入具有 ManyToOne 关系的模型

How to insert models with ManyToOne relationship using Rest framework Django

我正在学习 Django 休息框架,如果可能的话,我希望实现以下功能,例如,如果这是第一次拿到停车罚单,我想为该车牌号创建一个帐户违规,如果存在车牌号的帐户,我想将违规添加到该帐户。

结果:

{
"id": 12,
"account_number": "0350a6ec6",
"pin_number": "54fe8e",
"plate_number": "963874",
"plate_state": "AL",
"created": "2022-01-28T16:07:26Z",
"violations": [
  {
    "id": 3,
    "violation_number": "bd48668bdbf8",
    "violation_description": "bad place to park",
    "ticket_location": "ma",
    "violation_date": "2022-01-28T21:10:25Z",
    "violation_fine": "966.00",
    "violation_due": "2022-01-28T21:10:35Z"
  }

我的Models.py

from datetime import datetime, timedelta
from django.db import models
from .utils import generate_account_number, generate_account_pin, 
generate_violation_number

class Account(models.Model):
account_number = models.CharField(max_length=9, unique=True, blank=True, null=True, 
editable=False)
pin_number = models.CharField(max_length=6, blank=True, null=True, editable=False)
plate_number = models.CharField(max_length=8, blank=False, null=False)
plate_state = models.CharField(max_length=2,blank=False, null=False)
created = models.DateTimeField(default=datetime.now())

class Meta:
    ordering = ('-created',)

def __str__(self):
    return self.account_number

def get_absolute_url(self):
    return f'/{self.account_number}/'

def save(self, *args, **kwargs):
    self.account_number = generate_account_number()
    self.pin_number = generate_account_pin()
    super(Account, self).save(*args, **kwargs)


 class Violation(models.Model):
violation_number = models.CharField(max_length=12, unique=True,blank=True, null=True, 
editable=False)
violation_description = models.CharField(max_length=250)
ticket_location = models.CharField(max_length=250)
violation_date = models.DateTimeField(default=datetime.now())
violation_fine = models.DecimalField(max_digits=6, decimal_places=2)
violation_due = models.DateTimeField(default=datetime.now())
account = models.ForeignKey(Account, related_name='violations', 
on_delete=models.CASCADE)

class Meta:
    ordering = ('-violation_date',)

def __str__(self):
    return self.violation_number

def save(self, *args, **kwargs):
    self.violation_number = generate_violation_number()
    super(Violation, self).save(*args, **kwargs)

Serializer.py

from rest_framework import serializers
from .models import Account, Violation

class ViolationSerializer(serializers.ModelSerializer):
class Meta:
    model = Violation
    fields = (
        'id',
        'violation_number',
        'violation_description',
        'ticket_location',
        'violation_date',
        'violation_fine',
        'violation_due'
    )


class AccountSerializer(serializers.ModelSerializer):
violations = ViolationSerializer(many=True, read_only=True)

class Meta:
    model = Account
    fields = (
        'id',
        'account_number',
        'pin_number',
        'plate_number',
        'plate_state',
        'created',
        'violations'
    )

Views.py

from dataclasses import fields
from datetime import datetime
from django.http import Http404
from django.shortcuts import render
from rest_framework.views import APIView
from .models import Account, Violation
from .serializers import AccountSerializer
from rest_framework.response import Response
from .serializers import AccountSerializer, ViolationSerializer
from rest_framework.decorators import api_view
from rest_framework import status
from rest_framework.parsers import JSONParser 
from .utils import generate_account_number, generate_account_pin
# Create your views here.
class AccountsList(APIView):
def get(self, request, format=None):
    accounts = Account.objects.all()
    serializer = AccountSerializer(accounts, many= True)
    return Response(serializer.data)

def post(self, request, *args, **kwargs):
    pass #not sure what to do here


class AccountDetail(APIView):
def get_object(self, accn):
    try:
        return Account.objects.get(account_number = accn)
    except Account.DoesNotExist:
        raise Http404

def get(self, request, accn, format=None):
    account = self.get_object(accn)
    serializer = AccountSerializer(account)
    return Response(serializer.data)

我创建了一些函数来生成帐号、pin 和违规编号,我能够从 django 创建帐户,我知道我必须重写一些方法但我不确定哪些方法以及是否有任何改进我的代码的建议那也太好了。

我可以自己解决问题,我用 post 方法做到了:

def post(self, request, format=None):
    pn = request.data.get('plate_number')
    ps = request.data.get('plate_state')
    vd = request.data.get('violation_description')
    tl = request.data.get('ticket_location')
    vf = request.data.get('violation_fine')

    try:
        vaccount = Account.objects.filter(plate_number = pn, plate_state = ps)
      
        vserializer = vserializer = ViolationSerializer(data = {
                'violation_description': vd,
                'ticket_location': tl,
                'violation_fine': vf
            })
        aserializer = AccountSerializer(data = {
                'plate_number': pn,
                'plate_state': ps
            })

        if vaccount.exists():                
            if vserializer.is_valid():
                vserializer.save(account = vaccount.get())
                return Response({"status": "success", "data": vserializer.data}, status=status.HTTP_200_OK)             
        else:
            if(aserializer.is_valid()):
                aserializer.save()
                account = Account.objects.get(plate_number = aserializer.validated_data['plate_number'], plate_state = aserializer.validated_data['plate_state'])
                if vserializer.is_valid():
                    vserializer.save(account = account)
                return Response({"status": "success", "data": aserializer.data}, status=status.HTTP_200_OK)
            else:
                return Response({"status": "error", "data": aserializer.errors}, status=status.HTTP_400_BAD_REQUEST)        
    except Account.DoesNotExist:
        raise Http404

现在,如果该帐户存在,它会将违规添加到该帐户,如果不存在,它将创建该帐户,然后将违规添加到该帐户。