I have this model:
class AgentDetail(MethodID):
first_name = models.CharField(max_length=50, blank=True, null=True, unique=True)
last_name = models.CharField(max_length=50, unique=True, null=True)
email = models.EmailField(null=False)
authen_method = models.ForeignKey(AuthMethodID, on_delete=models.CASCADE)
country_code = models.BigIntegerField(default=1)
mobile_number = models.BigIntegerField(null=False)
sms_provider = models.CharField(max_length=50, null=True)
active_status = models.BooleanField(default=True)
created_time = models.DateTimeField(default=now, editable=False)
created_by = models.CharField(max_length=50)
updated_time = models.DateTimeField(auto_now=True)
updated_by = models.CharField(max_length=50)
and this serializer:
class AgentSerializer(serializers.ModelSerializer):
class Meta:
model = AgentDetail
fields = [
"first_name",
"last_name",
"email",
"authen_method",
"mobile_number",
"sms_provider",
]
and this views.py:
#api_view(["POST"])
def create_agent(request):
if request.method == "POST":
serializer = AgentSerializer(data=request.data, many=False)
if serializer.is_valid():
serializer.save()
request_data = serializer.data
# AgentDetail.objects.update_or_create(
# created_by=request_data["first_name"] + request_data["last_name"],
# updated_by=request_data["first_name"] + request_data["last_name"],
# )
return Response(status=status.HTTP_200_OK)
error = Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return error
As in serializer I'm not passing created_by field and I need that field gets value of first_name+last_name which are coming from serializer data.I'm new to DRF.
as said in docs you can pass additional attributes to save method.
views.py
#api_view(["POST"])
def create_agent(request):
if request.method == "POST":
serializer = AgentSerializer(data=request.data, many=False)
if serializer.is_valid():
request_data = serializer.validated_data
serializer.save(
created_by=request_data["first_name"] + request_data["last_name"],
updated_by=request_data["first_name"] + request_data["last_name"],
)
return Response(status=status.HTTP_200_OK)
error = Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return error
you can access the validated_data in create method, and add any extra data you want.
serializer.py
class AgentSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
first_name = validated_data.get('first_name', '')
last_name = validated_data.get('last_name', '')
validated_data.update(dict(
created_by=first_name+last_name,
updated_by=first_name+last_name
))
return super().create(validated_data)
Related
I want to implement the 'user_id' to be automatically saved at the backend without receiving it from the client. (when create object!)
This is my code.
models.py
class User(AbstractUser):
username = None
email = models.EmailField(max_length=255, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
social_profile = models.URLField(null=True,blank=True)
realname = models.CharField(max_length=50, blank=True)
nickname = models.CharField(max_length=50, null=True, unique=True)
address = models.CharField(max_length=200, blank=True)
phone = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.email
class Item(models.Model):
user_id = models.ForeignKey(User, related_name='item_sets', on_delete=models.CASCADE)
category_id = models.ForeignKey(Category, related_name='item_sets', on_delete=models.DO_NOTHING)
description = models.TextField()
feature = models.TextField()
product_defect = models.TextField()
size = models.CharField(max_length=6)
height = models.DecimalField(max_digits=4, decimal_places=1, default=0)
weight = models.DecimalField(max_digits=4, decimal_places=1, default=0)
condition = models.CharField(max_length=20)
price = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
sold_out = models.BooleanField(default=False)
def __str__(self):
return self.description
view.py
class ItemViewSet(ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['description'] # ?search=
ordering_fields = ['created_at'] # ?ordering=
ordering = ['-created_at']
authentication_classes = (JWTCookieAuthentication,)
# create
def create(self, request, *args, **kwargs):
city = request.data['city']
gu = request.data['gu']
dong = request.data['dong']
if city is not None and gu is not None and dong is not None:
location = Location.objects.get(
Q(city=city) & Q(gu=gu) & Q(dong=dong)
)
else:
return Response(
{"message": "주소정보를 모두 입력해주세요."},
status=status.HTTP_400_BAD_REQUEST
)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
new_item = Item.objects.get(id=serializer.data['id'])
headers = self.get_success_headers(serializer.data)
LocationSet.objects.create(item_id=new_item, location_id=location)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
# here!
def perform_create(self, serializer):
serializer.save(user_id=self.request.user)
serializers.py
class ItemSerializer(serializers.ModelSerializer):
photos = PhotoSerializer(source='photo_sets', many=True, read_only=True)
style_photos = StylePhotoSerializer(source='style_photo_sets', many=True, read_only=True)
user_id = serializers.ModelField(model_field=User()._meta.get_field('id'), required=False) #here!
class Meta:
model = Item
fields = '__all__'
# Photo, StylePhoto
def create(self, validated_data):
images_data = self.context['request'].FILES
item = Item.objects.create(**validated_data)
for photo_data in images_data.getlist('photos_data'):
Photo.objects.create(item_id=item, photo=photo_data)
for style_photo_data in images_data.getlist('style_photos_data'):
StylePhoto.objects.create(item_id=item, user_id=self.context['request'].user,
photo=style_photo_data)
print(User()._meta.get_field('id'))
return item
so I overrided perform_create() in views.py
and write 'user_id = serializers.ModelField(model_field=User()._meta.get_field('id'), required=False)' in serializers.py
but it doesn't work well like my intend...
correct user_id is 8. but my object has 18..:<
18 is just item_id, not user_id..
what should I do to fix this error?
Try this:
views.py : use the perform_create() method to save the user_id.
Note: the user must be authenticated so that we can get them from the request.
class ItemViewSet(ModelViewSet):
# your code ...
# create
def create(self, request, *args, **kwargs):
# your code code ...
def perform_create(self, serializer): # new
serializer.save(user_id=self.request.user)
serializers.py :
Get the user_id from the database and make it readonly as it is not supposed to be edited by the user:
class ItemSerializer(serializers.ModelSerializer):
# your code ..
user_id = serializers.ReadOnlyField(source='user_id.id') # new
class Meta:
model = Item
fields = '__all__'
# Photo, StylePhoto
def create(self, validated_data):
images_data = self.context['request'].FILES
item = Item.objects.create(**validated_data)
for photo_data in images_data.getlist('photos_data'):
Photo.objects.create(item_id=item, photo=photo_data)
for style_photo_data in images_data.getlist('style_photos_data'):
StylePhoto.objects.create(item_id=item,photo=style_photo_data) # new
print(User()._meta.get_field('id'))
return item
I would also recommend you change the user_id field to something like owner to prevent future confusion.
My point is to implement the post method with a nested object which has just ID. When I use all fields of a nested object post method works fine. But I'd like to pass just one field and it is ID, other fields gotta be unrequired
Now I'm getting the error like
NOT NULL constraint failed: article_article.author_id
models.py
class Author(models.Model):
first_name = models.CharField(max_length=20, blank=True, null=True)
last_name = models.CharField(max_length=20, blank=True, null=True)
nickname = models.CharField(max_length=20, blank=True, null=True)
def __str__(self):
return self.nickname
class Article(models.Model):
title = models.CharField(max_length=120, unique=True)
description = models.TextField(blank=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, blank=True)
def __str__(self):
return self.title
views.py
class ArticleView(APIView):
def get(self, request, pk=None):
if pk:
article = Article.objects.get(pk=pk)
serializer = ArticleSerializer(article, many=False)
else:
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
data = request.data
serializer = ArticleSerializer(data=data)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '' created successfully".format(article_saved.title)},
status=status.HTTP_201_CREATED)
serializers.py
class AuthorSerializer(serializers.Serializer):
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
nickname = serializers.CharField(required=False)
class ArticleSerializer(serializers.Serializer):
title = serializers.CharField(max_length=120)
description = serializers.CharField()
author = AuthorSerializer(required=False)
def create(self, validated_data):
author_data = validated_data.pop('author', None)
if author_data:
author = Author.objects.get_or_create(**author_data)[0]
validated_data['author'] = author
return Article.objects.create(**validated_data)
I got it. I should just have added to a serializer the field ID
class AuthorSerializer(serializers.Serializer):
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
nickname = serializers.CharField(required=False)
id = serializers.IntegerField()
I am trying to post multiple data into my DataBase Using Django Rest framework (DRF).
AttributeError at /apiv2/api/processorder/order/
Got AttributeError when attempting to get a value for field subcategory on serializer MyProcessOrderSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the list instance.
Original exception text was: 'list' object has no attribute 'subcategory'.
models.py
class SubCategory(models.Model):
category = models.ForeignKey(Category, related_name='subcategory', on_delete=models.CASCADE)
name = models.CharField("Food Name", max_length=50, help_text="Name of The Food")
price = models.DecimalField("Food Price", max_digits=5, decimal_places=2)
quantity = models.PositiveIntegerField("Qty.", help_text="Quantity of the food Item you want")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.name}'
class Meta:
verbose_name = 'SubCategory'
verbose_name_plural = 'SubCategories'
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
bike = models.ForeignKey(User, related_name='bike', on_delete=models.CASCADE, blank=True, null=True)
package = models.ForeignKey(PackageType, related_name='package', on_delete=models.CASCADE, blank=True, null=True)
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0000.0)
qty = models.PositiveIntegerField(default=1)
shipping_address = models.CharField("Delivery Address", max_length=150)
paid = models.BooleanField(default=False)
ordernote = models.TextField("Order Notes", null=True)
shipped = models.BooleanField(default=False)
complete = models.BooleanField(default=False)
received = models.BooleanField(default=False)
refund_requested = models.BooleanField(default=False)
refund_granted = models.BooleanField(default=False)
ref_code = models.CharField(max_length=20, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return '{}'.format(self.id)
def order(self):
if not hasattr(self, '_order'):
self._order = self.order.all()
return self._order
'''
def get_total_cost(self):
total_cost = sum(orders.get_cost() for orders in self.order.all())
return total_cost
'''
class ProcessOrder(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
order = models.ForeignKey(Order, related_name='order', on_delete=models.CASCADE)
quantity = models.PositiveIntegerField("Qty.", default=1, help_text="Quantity of the food Item you want")
#category = models.ForeignKey(Category, related_name='category', on_delete=models.CASCADE)
subcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.order} -- {self.subcategory.name}'
serializers.py
class MyProcessOrderSerializer(serializers.ModelSerializer):
#subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
#subcategory_set = SubCategoryOrderSerializer(many=True)
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
return ProcessOrder.objects.create(**validated_data)
view.pf
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def processorder_view(request):
orderuser = User.objects.get(id=request.user.id)
serializer = MyProcessOrderSerializer(data=request.data, many=True)
if serializer.is_valid():
order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
order.save()
processorder = serializer.save(order=order, user=orderuser)
return Response(MyProcessOrderSerializer(processorder).data, status=status.HTTP_201_CREATED)
else: #return Response("Process Order Created Successfully")
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I am now trying to make a POST such as this but getting the above error.
[{
"quantity": 16,
"subcategory": 1
},
{
"quantity": 14,
"subcategory": 3
}
]
You have to explicitly specify the relation in the serializer either with one of the built-in serializer:
Serializer relations
class MyProcessOrderSerializer(serializers.ModelSerializer):
# StringRelatedField and PrimaryKeyRelatedField are some of the built in ones.
subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)
user = serializer.PrimaryKeyRelatedField()
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
# If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
return ProcessOrder.objects.create(**validated_data)
or by creating a custom subcategory serializer and then in serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'email', 'password', 'first_name', 'last_name')
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
fields = # whatever fields youd'e like to include
class MyProcessOrderSerializer(serializers.ModelSerializer):
# StringRelatedField is One of the built in ones.
sybcategory = SubCategorySerializer()
user = UserSerializer()
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
# If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
return ProcessOrder.objects.create(**validated_data)
And, I noticed you have Foreign Key to User in process order and order itself,
You could delete the user field from the process order and access it via the order relation, for that you can specify the user field in the subcategory serializer and the subcategory serializer in the process order serializer as I showed above.
And if I understand the purpose of creating a process order model, the relation should be a One to One and not Foreign key, But maybe I'm not seeing the whole picture here.
I think the problem apear in request.data in this line :
serializer = MyProcessOrderSerializer(data=request.data, many=True)
You should loop throught your object list and pass just the object not the whole list .
exemple :
{ "list_":[{"quantity": 7 ,"subcategory": 3}, {"quantity": 7 ,"subcategory": 3}] }
To get the first object from the request :
request.data.get('list_')[0]
I was able to solve the problem with this code both in my views and serialize
views.py
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def processorder_view(request):
orderuser = User.objects.get(id=request.user.id)
data = request.data
order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
if isinstance(data, list):
serializer = MyProcessOrderSerializer(data=request.data, many=True)
else:
serializer = MyProcessOrderSerializer(data=request.data)
if serializer.is_valid():
processorder = serializer.save(order=order, user=request.user)
return Response(status=status.HTTP_201_CREATED)
#return HttpResponse("Question created", status=201)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class MyProcessOrderSerializer(serializers.ModelSerializer):
#subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
#subcategory_set = SubCategoryOrderSerializer(many=True)
#subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
return ProcessOrder.objects.create(**validated_data)
Then, I was able to send multiple data with this sample.
[
{
"subcategory": 1,
"quantity": 12
},
{
"subcategory": 3,
"quantity": 12
}
]
Following are my files. It is simply adding products based on subcategories and categories. Everything is working fine but the data is not being saved in the database. I am not sure where I am going wrong.
models.py
from django.db import models
class Category(models.Model):
category = models.CharField(max_length=200)
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
class Meta:
unique_together = ('parent' , 'category')
def __str__(self):
return self.category
class SubCategory(models.Model):
subcategory = models.CharField(max_length=200)
category = models.ForeignKey('Category', null=True, blank=True)
parent = models.ForeignKey('self', blank=True, null=True, related_name='subchilren')
class Meta:
unique_together = ('parent' , 'subcategory')
def __str__(self):
return self.subcategory
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey('Category', null=True, blank=True)
subcategory = models.ForeignKey('SubCategory', null=True, blank=True)
def __str__(self):
return self.name
views.py
class AddProducts(APIView):
serializer_class = AddProductsSerializer
def post(self, request, format=None):
data = request.data
serializer = AddProductsSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
return Response(new_data)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
serializers.py
class AddProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'category', 'subcategory')
def create(self, validated_data):
return Product.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.category = validated_data.get('category', instance.category)
instance.subcategory = validated_data.get('subcategory', instance.subcategory)
instance.save()
return instance
if serializer.is_valid(raise_exception=True):
serializer.save()
new_data = serializer.data
return Response(new_data)
add serializer.save() will call serializer create method when serializer has no instance.
I am using Django 1.8.4 and Django rest framework 3.2.3. Because I want override "username" field I had to use "AbstractBaseUser"
The used model is:
class Users(AbstractBaseUser):
username = models.EmailField(max_length=75, null=False, blank=False, unique=True)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=70, null=True, blank=True)
tel_number = models.IntegerField(null=True, blank=True)
address = models.CharField(max_length=250, null=True, blank=True)
user_image = models.ImageField(upload_to='user_avatar', blank=True, null=True)
date_time = models.DateTimeField(auto_now=True, null=True, blank=True)
activated = models.BooleanField(default=False)
def __unicode__(self):
return self.username
class Meta:
ordering = ['-id']
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['tel_number']
Now I want create new user with new token:
if request.method == 'POST':
serializer = UserSerializer(data=request.data)
data = {}
if serializer.is_valid():
user = serializer.save()
token, created = Token.objects.get_or_create(user=user)
data['token'] = token
data = serializer.data
return Response(data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and my serializer is :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'tel_number', 'address', 'user_image')
But I get this error on "Create Token Lines":
Cannot query "a#gmail.com": Must be "User" instance.
You are not passing the user instance to Token.
Can you try this:
In routers.py
from rest_framework import routers
from .viewsets import UserSeralizerViewSets
router = routers.DefaultRouter()
router.register(r'users', UserSeralizerViewSets)
In urls.py
from .routers import router
urlpatterns = [
url(r'^', include(router.urls)),
]
In viewsets.py
class UserSeralizerViewSets(viewsets.ModelViewSet):
serializer_class = UserSeralizer
queryset = Users.objects.all()
def create(self, request, *args, **kwargs):
data = {}
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
token, created = Token.objects.get_or_create(user=user)
data['token'] = token.key
return Response(data, status=status.HTTP_201_CREATED)
The answer of seenu s is well but i use this line in settings.py and worked .
AUTH_USER_MODEL = 'users.Users'
Users.Users is (myappname.mymodelname)
I find this on Django doc.