You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django非REST框架API中无法添加外键关联的联系电话

解决Django API添加外键关联联系电话的问题

我最近在搞一个不用REST Framework的Django API,遇到个头疼的问题:POST新增联系人时,除了外键关联的联系电话(想支持加一个或者多个),其他数据都能正常进数据库,唯独联系电话死活加不上。折腾了半天,终于找到问题所在,给大家分享下解决方案:

先看我之前的错误代码

views.py

@method_decorator(csrf_exempt)
def phonebook_list(request):
    if request.method == 'GET':
        phonebooklist = PhoneBook.objects.all()
        serialized_data = [pb.to_json() for pb in phonebooklist]
        return JsonResponse(serialized_data, safe=False)
    elif request.method == 'POST':
        data= request.body.decode('utf8')
        data= json.loads(data)
        try:
            new_contact=PhoneBook(name=data["name"], address=data["address"], email=data["email"], note=data["note"])
            new_contact.save()
            new_contact_number=ContactNumber(
                contact_number=data["contact_number"], 
                #No Contact Numbers Added 
                # It should add one or more contact numbers
                number_id=data[PhoneBook.id] 
                #It should add the contact number/s to the contact name added together
            )
            contact_number.save()
            return JsonResponse({"created": data}, safe= False)
        except:
            return JsonResponse({"error":"not valid data"}, safe=False)

models.py

class PhoneBook(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=100, default='address')
    email = models.CharField(max_length=50, default='email')
    note = models.CharField(max_length=100, default='note')

    def to_json(self):
        contact_numbers = [c.contact_number for c in self.contact_numbers.all()]
        return {
            'name': self.name,
            'email': self.email,
            'address': self.address,
            'note': self.note,
            'contact_numbers': contact_numbers
        }

    def __str__(self):
        return self.name

class ContactNumber(models.Model):
    number = models.ForeignKey(PhoneBook, related_name="contact_numbers")
    contact_number= models.CharField(max_length=30)

    def __str__(self):
        return self.contact_number

问题出在哪?

  1. 外键关联错误:number_id=data[PhoneBook.id]这写法完全错了!PhoneBook.id是模型的字段类,根本不是请求数据里的键,应该用刚保存的new_contact.id——毕竟new_contact.save()之后就有主键ID了,直接关联这个ID才对。
  2. 变量名写错+不支持多个电话:创建的对象是new_contact_number,但保存的却是contact_number.save(),这直接会报变量未定义的错误;而且代码只处理单个电话,没法支持多个。
  3. 异常处理太敷衍:直接一个except:捕获所有异常,连具体错在哪都不知道,调试起来全靠猜。

修复后的正确代码

先补全models.py的ForeignKey参数(Django2.0+必须加on_delete)

class ContactNumber(models.Model):
    # 加上on_delete参数,这里用CASCADE表示删除联系人时同步删除电话
    number = models.ForeignKey(PhoneBook, related_name="contact_numbers", on_delete=models.CASCADE)
    contact_number= models.CharField(max_length=30)

    def __str__(self):
        return self.contact_number

重写后的views.py(改用类视图更规范,也兼容函数视图写法)

import json
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from .models import PhoneBook, ContactNumber
from django.utils.decorators import method_decorator
from django.views import View

@method_decorator(csrf_exempt, name='dispatch')
class PhoneBookListView(View):
    def get(self, request):
        phonebooklist = PhoneBook.objects.all()
        serialized_data = [pb.to_json() for pb in phonebooklist]
        return JsonResponse(serialized_data, safe=False)

    def post(self, request):
        try:
            # 解析请求体
            data = json.loads(request.body.decode('utf8'))
            
            # 创建主联系人:用objects.create更简洁,用get带默认值避免可选字段未传报错
            new_contact = PhoneBook.objects.create(
                name=data["name"],
                address=data.get("address", "address"),
                email=data.get("email", "email"),
                note=data.get("note", "note")
            )
            
            # 处理联系电话:兼容单个字符串和列表两种输入
            contact_numbers = data.get("contact_numbers", [])
            if isinstance(contact_numbers, str):
                contact_numbers = [contact_numbers]
            
            # 批量创建联系电话,效率更高,还能过滤空号码
            number_objects = [
                ContactNumber(contact_number=num.strip(), number=new_contact)
                for num in contact_numbers if num.strip()
            ]
            ContactNumber.objects.bulk_create(number_objects)

            # 返回包含联系电话的完整创建结果
            return JsonResponse(new_contact.to_json(), safe=False)
        
        # 捕获必填字段缺失的错误
        except KeyError as e:
            return JsonResponse({"error": f"缺少必填字段: {str(e)}"}, status=400)
        # 捕获其他异常,返回具体错误信息
        except Exception as e:
            return JsonResponse({"error": f"创建失败: {str(e)}"}, status=500)

测试用的请求体示例

Postman里选POST,请求体用JSON格式,支持单个或多个电话:

多个电话的情况

{
    "name": "张三",
    "address": "北京市朝阳区",
    "email": "zhangsan@example.com",
    "note": "好朋友",
    "contact_numbers": ["13800138000", "13900139000"]
}

单个电话的情况

{
    "name": "李四",
    "address": "上海市浦东新区",
    "email": "lisi@example.com",
    "note": "同事",
    "contact_numbers": "13700137000"
}

这样修改后,联系电话就能正常关联到对应的联系人,不管是一个还是多个都能存入数据库啦~

内容的提问来源于stack exchange,提问作者bossajie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:17:48