Django ReST引发TypeError

时间:2018-06-20 23:28:15

标签: django django-rest-framework

我正在尝试django ReST框架API,当我尝试将一些数据发布到django时遇到问题。我已经在ReST框架的通用视图的帮助下创建了API视图,并且有了基本模型。这是我得到的错误:

TypeError at /api/meals/
 Got a `TypeError` when calling `Meal.objects.create()`. This may be 
 because you have a writable field on the serializer class that is not a 
 valid argument to `Meal.objects.create()`. You may need to make the 
field read-only, or override the MealSerializer.create() method to 
handle this correctly.
Original exception was:
Traceback (most recent call last):
File "/Users/mickael/Desktop/Dev/foody-api/lib/python3.6/site- 
packages/rest_framework/serializers.py", line 940, in create
instance = ModelClass.objects.create(**validated_data)
File "/Users/mickael/Desktop/Dev/foody-api/lib/python3.6/site- 
packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/mickael/Desktop/Dev/foody-api/lib/python3.6/site- 
packages/django/db/models/query.py", line 415, in create
obj = self.model(**kwargs)
File "/Users/mickael/Desktop/Dev/foody-api/lib/python3.6/site- 
packages/django/db/models/base.py", line 495, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" 
% kwarg)
TypeError: 'user' is an invalid keyword argument for this function`

这是我的models.py

def upload_status_image(instance, filename):
return 
"status/{restaurant}/{filename}"
.format(restaurant=instance.restaurant.user, 
filename=filename)


 class Restaurant(models.Model):
   user = models.OneToOneField(User, on_delete=models.CASCADE, 
   related_name='restaurant')
   name = models.CharField(max_length=500)
   phone = models.CharField(max_length=500)
   address = models.CharField(max_length=500)
   logo = models.ImageField(upload_to='restaurant_logo/', blank=False)

  def __str__(self):
     return self.name

  class Customer(models.Model):
   user = models.OneToOneField(User, on_delete=models.CASCADE, 
   related_name='customer')
   avatar = models.CharField(max_length=500)
   phone = models.CharField(max_length=500, blank=True)
   address = models.CharField(max_length=500, blank=True)

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

  class Driver(models.Model):
   user = models.OneToOneField(User, on_delete=models.CASCADE, 
   related_name='driver')
   avatar = models.CharField(max_length=500)
   phone = models.CharField(max_length=500, blank=True)
   address = models.CharField(max_length=500, blank=True)
   location = models.CharField(max_length=500, blank=True)

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


    class MealCategory(models.Model):
     restaurant = models.ForeignKey(Restaurant,on_delete=models.CASCADE)
     name = models.CharField(max_length=500, default='Starter', null = 
     True , blank = True)
     def __str__(self):
       return self.name

     class Meal(models.Model):
     restaurant      = 
     models.ForeignKey(Restaurant,on_delete=models.CASCADE, null = True 
      , blank = True)
    category        = models.ForeignKey(MealCategory, 
    related_name='meal_category', on_delete=models.CASCADE,null = True , 
     blank = True)
    name            = models.CharField(max_length=120)
    description     = models.TextField()
    image           = models.ImageField(upload_to=upload_status_image, 
    blank=False, null=True)
    price           = models.FloatField(default=0)
    publish         = models.DateField(auto_now=False, 
    auto_now_add=False)
    updated         = models.DateTimeField(auto_now=True, 
    auto_now_add=False)
    timestamp       = models.DateTimeField(auto_now=False, 
    auto_now_add=True)


     def __str__(self):
       return self.name

这是我的serializers.py

class UserPublicSerializer(serializers.ModelSerializer):
username = serializers.CharField(required=False, allow_blank=True, read_only=True)
class Meta:
    model = User
    fields = [
        'username',
        'first_name',
        'last_name',
        ]

 class RestaurantSerializer(serializers.ModelSerializer):
   user = UserPublicSerializer(read_only=True)
   logo = serializers.SerializerMethodField()

   def get_logo(self, restaurant):
    request = self.context.get('request')
    logo_url = restaurant.logo.url
    return request.build_absolute_uri(logo_url)

class Meta:
    model = Restaurant
    fields = [
    "id",
    "user",
    "name",
    "phone",
    "address",
    "logo"]


 class MealCategorySerializer(serializers.ModelSerializer):
   class Meta:
     model = MealCategory
     fields = [ "name" ]



 class MealSerializer(serializers.ModelSerializer):
    url             = serializers.HyperlinkedIdentityField(
                        view_name='restaurant-api:detail',
                        lookup_field='id',

                        )
restaurant      = RestaurantSerializer(read_only=True)
category        = MealCategorySerializer(read_only=True)
publish         = serializers.DateField(default=timezone.now())

def get_image(self, product):
    request = self.context.get('request')
    image_url = product.image.url
    return request.build_absolute_uri(image_url)



class Meta:
    model = Meal
    fields = [
        'url',
        'id',
        'restaurant',
        'category',
        'name',
        'description',
        'image',
        'price',
        'publish',
        'updated',
        'timestamp'
    ]

这是我的views.py

class MealDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset            = Meal.objects.all()
serializer_class    = MealSerializer
lookup_field        = 'id'
permission_classes  = [IsOwnerOrReadOnly]





class MealListCreateAPIView(generics.ListCreateAPIView):
  queryset            = Meal.objects.all()
  serializer_class    = MealSerializer
  permission_classes  = [permissions.IsAuthenticatedOrReadOnly]


def get_queryset(self):
    request = self.request
    qs = Meal.objects.filter(restaurant = request.user.restaurant).order_by("-id")

    query = request.GET.get('q')
    if query is not None:
        qs = qs.filter(name__icontains=query, description__icontains=query)
    return qs



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

如果您知道如何解决此问题,谢谢您的帮助

2 个答案:

答案 0 :(得分:0)

在您的Meal模型中,没有定义user字段,它也不是MealSerializer的一部分。但是在perform_create()中,您将其作为命名参数传递。

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

错误消息指示它,

TypeError: 'user' is an invalid keyword argument for this function`

解决方案是您定义模型中的字段或将其从函数调用中删除。我认为您想要模型中的一个字段。

答案 1 :(得分:0)

perform_create()中的MealListCreateAPIViewcurrent logged-in user实例传递到相应的序列化程序(MealSerializer),并尝试在{{1}中创建一个Meal实例}。

该方法的问题是
1.您没有在DB模型中用User定义任何FK关系
2.您没有在Meal中定义user字段

因此,我建议在MealSerializer

中定义一个User关系
Meal

,然后使用 from django.contrib.auth.models import User class Meal(models.Model): # ..... # other fields user = models.ForeignKey(User)类将已登录的用户实例传递给序列化器

CurrentUserDefault()


现在,您可以从class MealSerializer(serializers.ModelSerializer): # .. other fields user = serializers.CurrentUserDefault() 中删除perform_create()方法,因为MealListCreateAPIView为您完成了这项工作