我正在尝试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)
如果您知道如何解决此问题,谢谢您的帮助
答案 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()
中的MealListCreateAPIView
将current 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
为您完成了这项工作