Django Rest Framework发布嵌套使用带有请求的文件模块示例

时间:2017-06-05 22:05:47

标签: django python-3.x django-rest-framework

对不起,我有问题,任何人都可以帮助我。

我的模特有:

from django.db import models
from django.contrib.auth.models import User
import uuid


def uuid_generator():
    return str(uuid.uuid4())


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile_user')
    mobile = models.CharField(max_length=20)
    alamat = models.TextField(blank=True)
    phone = models.CharField(max_length=20, blank=True)
    foto = models.ImageField(upload_to='profile', blank=True)

    def __str__(self):
        return self.user.username


class Rumah(models.Model):
    JENIS_CHOICES = (
        ('rumah', 'Rumah besar'),
        ('petakan', 'Rumah petakan'),
        ('apartement', 'Apartement'),
        ('kost', 'Kost-Kostan')
    )

    WAKTU_CHOICES = (
        ('bulanan', 'Bulanan'),
        ('tahunan', 'Tahunan'),
    )

    STATUS_CHOICES = (
        ('tersedia', 'Tersedia'),
        ('terisi', 'Sudah Terisi'),
        ('ditutup', 'Di Tutup'),
    )

    pemilik = models.ForeignKey(User, on_delete=models.CASCADE, related_name='rumah_user')
    kode = models.CharField(unique=True, max_length=150)
    jenis = models.CharField(max_length=12, choices=JENIS_CHOICES, default='rumah')
    waktu = models.CharField(max_length=10, choices=WAKTU_CHOICES, default='bulanan')
    harga = models.PositiveIntegerField()
    alamat = models.TextField()
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='tersedia')
    keterangan = models.TextField(blank=True)

    def __str__(self):
        return self.kode

    def save(self, *args, **kwargs):
        self.kode = uuid_generator()
        super(Rumah, self).save(*args, **kwargs)


class Foto(models.Model):
    rumah = models.ForeignKey(Rumah, on_delete=models.CASCADE, related_name='foto_rumah')
    penampakan = models.ImageField(upload_to='penampakan', blank=True)
    keterangan = models.TextField(blank=True)

    def __str__(self):
        return self.rumah.kode

注意: Rumah 如英语中的 House Foto ,如英语中的图片

我的观点如下:

from django.contrib.auth.models import User
from produk.models import Profile, Rumah, Foto
from .serializers import UserSerializer, ProfileSerializer, RumahSerializer, FotoSerializer
from .permissions import IsOwnerOrReadOnly, IsHasProfile, IsRumahOrReadOnly
from rest_framework import mixins
from rest_framework import generics
from rest_framework import permissions


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class ProfileList(generics.ListCreateAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


class ProfileDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer


class RumahList(generics.ListCreateAPIView):
    queryset = Rumah.objects.all()
    serializer_class = RumahSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(pemilik=self.request.user)


class RumahDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Rumah.objects.all()
    serializer_class = RumahSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)


class FotoList(generics.ListCreateAPIView):
    queryset = Foto.objects.all()
    serializer_class = FotoSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)


class FotoDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Foto.objects.all()
    serializer_class = FotoSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsRumahOrReadOnly)

我有一个类似的序列化器:

from django.contrib.auth.models import User
from rest_framework import serializers
from produk.models import Profile, Rumah, Foto


class UserSerializer(serializers.HyperlinkedModelSerializer):
    rumah_user = serializers.HyperlinkedRelatedField(many=True, view_name='rumah-detail', read_only=True)
    profile_user = serializers.HyperlinkedRelatedField(many=False, view_name='profile-detail', read_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'is_active', 'rumah_user', 'profile_user')


class ProfileSerializer(serializers.ModelSerializer):
    user = serializers.ReadOnlyField(source='user.username')

    class Meta:
        model = Profile
        fields = ('id', 'user', 'alamat', 'mobile', 'phone', 'foto')


class FotoSerializer(serializers.ModelSerializer):
    # rumah = serializers.ReadOnlyField(source='rumah.kode')

    class Meta:
        model = Foto
        fields = ('id', 'rumah', 'penampakan', 'keterangan')


class RumahSerializer(serializers.ModelSerializer):
    pemilik = serializers.ReadOnlyField(source='pemilik.username')
    #foto_rumah = serializers.HyperlinkedRelatedField(many=True, view_name='foto-detail', read_only=True)
    foto_rumah = FotoSerializer(many=True)

    class Meta:
        model = Rumah
        fields = ('id', 'pemilik', 'jenis', 'waktu', 'harga', 'alamat', 'status', 'keterangan', 'foto_rumah')

    def create(self, validated_data):
        fotos_data = validated_data.pop('foto_rumah')
        print(validated_data)
        rumah = Rumah.objects.create(**validated_data)
        for foto_data in fotos_data:
            Foto.objects.create(rumah=rumah, **foto_data)
        return rumah 

当我尝试使用请求模块时:

import requests
from requests.auth import HTTPBasicAuth

url = 'http://127.0.0.1:8000/rumah/'

files = {'penampakan': open('C:\\Users\\yanz\\Pictures\\Campuran\\test.png', 'rb')}
data =  {
        "pemilik": "admin",
        "jenis": "rumah",
        "waktu": "bulanan",
        "harga": 3,
        "alamat": "r",
        "status": "tersedia",
        "keterangan": "4",
        "foto_rumah": [
            {
                "penampakan": files,
                "keterangan": "a"
            }
        ]
    }
r = requests.post(url, data=data, files=files, auth=HTTPBasicAuth('admin', 'password123'))

print(r.text)

结果:

{"id":11,"pemilik":"admin","jenis":"rumah","waktu":"bulanan","harga":3,"alamat":"r","status":"tersedia","keterangan":"4","foto_rumah":[]}

来自模特Foto的Foto(foto_rumah)数据未保存。解决方案是什么?如何使用文件发布嵌套数据?

...谢谢

1 个答案:

答案 0 :(得分:0)

嵌套序列化程序尚未使用表单编码数据。 上传图片仅适用于开箱即用的表格编码数据。

我想您需要在特定的非嵌套入口点上传图像或使用JSON中的base64编码文件。 我记得我已经看到第三方处理base64文件,但无法再找到它。