I'm working on an app that lets you track your expenses and I'm trying to create an 'balnace' object when the user registers, but when I try so I get an Error: Cannot assign "15": "Balance.user_id" must be a "Users" instance.
Model
class Balance(models.Model):
balance = models.FloatField(
verbose_name="Balance", blank=False, null=False)
user_id = models.ForeignKey(
'expenseApi.Users', verbose_name="Usuario", blank=False, null=False, on_delete=models.PROTECT)
def __str__(self):
return '{}'.format(self.pk)
serializer
class RegisterSerializer(serializers.ModelSerializer):
tokens = serializers.SerializerMethodField()
email = serializers.EmailField(max_length=50)
class Meta:
model = Users
fields= ['id', 'email', 'password', 'name', 'lastname', 'birthday', 'tokens']
extra_kwargs = {
'password': {
'write_only': True,
},
}
def get_tokens(self,user):
refresh = RefreshToken.for_user(user)
data = {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
return data
def create(self, request):
email= Users.objects.filter(email=request['email'])
if email:
raise serializers.ValidationError({'detail': 'El email ya esta en uso'})
user = Users.objects.create_user(email=request['email'],
password=request['password'],
name=request['name'],
lastname=request['lastname'],
birthday=request['birthday'])
user['balance'] = Balance.objects.create(balance=0,user_id=user.id)
return user
I didn't go in detail about logic on your code but I guess error based on your code at
user['balance'] = Balance.objects.create(balance=0,user_id=user.id)
should be
user['balance'] = Balance.objects.create(balance=0, user_id=user)
Since you named your ForeignKey user_id, this means that you can assign a User object to .user_id, or the primary key to .user_id_id:
user['balance'] = Balance.objects.create(
balance=0,
user_id_id = user.id
)
I would however advise to rename user_id to user, since now the field "hints" that it is an id, but it is not.
class Balance(models.Model):
balance = models.FloatField(verbose_name='Balance')
user = models.ForeignKey(
'expenseApi.Users',
verbose_name='Usuario',
on_delete=models.PROTECT
)
# …
Then we thus can set this with:
user['balance'] = Balance.objects.create(
balance=0,
user_id = user.id
)
Related
I have a Django REST project. I have a models User, Store and Warehouse.
And I have a module with marketplace parser, that gets data from marketplace API. In this module there is a class Market and a method "get_warehouses_list". This method returns a JSON with a STORE's warehouse list.
Examle answer:
{
"result": [
{
"warehouse_id": 1,
"name": "name1",
"is_rfbs": false
},
{
"warehouse_id": 2,
"name": "name2",
"is_rfbs": true
}
]
}
What I have to do is to make creating and updating methods to set and update this warehouse list into my MySQL DB (with creating an endpoint for setting and updating this data).
I don't know what is incorrect in my code, but when I send POST request to my endpoint in urls.py
router.register("", WarehouseApi, basename="warehouse")
I get 400 error instead of setting warehouse list into my DB.
My code:
user/models.py
class User(AbstractUser):
username = models.CharField(
max_length=150,
unique=True,
null=True)
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
unique=True,
editable=False)
store/models.py
`
class Store(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT)
name = models.CharField(max_length=128,
blank=True)
type = models.PositiveSmallIntegerField(
choices=MARKET,
default=1,
verbose_name="Type API")
api_key = models.CharField(max_length=128)
client_id = models.CharField(max_length=128)
warehouses/models.py
class Warehouse(models.Model):
store = models.ForeignKey(
Store,
on_delete=models.СASCAD, null=True)
warehouse_id = models.BigIntegerField(
unique = True,
null = True)
name = models.CharField(
max_length=150)
is_rfbs = models.BooleanField(default=False)
`
serializers.py
`
class WarehouseSerializer(serializers.ModelSerializer):
class Meta:
model = Warehouse
fields = '__all__'
store = serializers.CharField(max_length=50)
warehouse_id = serializers.IntegerField()
name = serializers.CharField(max_length=100)
is_rfbs = serializers.BooleanField()
is_default_warehouse = serializers.BooleanField()
class WarehouseUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Warehouse
fields = ('name', 'is_rfbs',)
def save(self, **kwargs):
self.instance.name = self.validated_data["name"]
self.instance.is_rfbs = self.validated_data["is_rfbs"]
self.instance.save
returself.instance
views.py
class WarehouseApi(ModelViewSet):
def get_queryset(self):
return Warehouse.objects.filter(
store__user_id=self.request.user.pk)\
.order_by('-warehouse_id')
def get_serializer_class(self):
if self.request.method in ("PUT", "PATCH"):
return WarehouseUpdateSerializer
return WarehouseSerializer
def create(self, request, *args, **kwargs):
st = Store.objects.filter(user=self.request.user, # getting all stores with marketplace type = 1
type=1)
for e in st:
api = Market(api_key=e.api_key, # call parser class Market
client_id=e.client_id)
data = api.get_warehouses_list() # call Market's method 'get_warehouses_list'
if len(data['result']) > 0:
for wh in data['result']:
alreadyExists = Warehouse.objects.filter( # check if warehouses with such ID already exists
warehouse_id=wh.get(
'warehouse_id')).exists()
if alreadyExists:
return Response({'message':'Warehouse ID already exists'})
else:
wh_data = {
'warehouse_id': wh.get('warehouse_id'),
'name': wh.get('name'),
'is_rfbs': wh.get('is_rfbs')
}
Warehouse.objects.create(**wh_data)
warehouses = Warehouse.objects.filter(
marketplace=1, store__in=st).order_by(
'-warehouse_id')
s = WarehouseSerializer(warehouses, many=True)
return Response(status=200, data=s.data)
else:
return Response(status=400,
data={"Error": "Store has no warehouses"})
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
api = Market(api_key=instance.store.api_key,
client_id=instance.store.client_id)
warehouses = Warehouse.objects.filter(store__user_id=self.request.user,
store__type=1) # get all store's warehouses
if warehouses:
for warehouse in warehouses:
r = api.get_warehouses_list() # call Market's method 'get_warehouses_list'
if len(r['result']) > 0:
for wh in r['result']:
if serializer.validated_data["name"] != wh['name']:
instance.name = wh['name']
instance.save(['name'])
if serializer.validated_data["is_rfbs"] != wh['is_rfbs']:
instance.name = wh['is_rfbs']
instance.save(['is_rfbs'])
serializer = WarehouseUpdateSerializer(instance)
return Response(serializer.data, {
'status': status.HTTP_200_OK,
'message': 'Warehouse updated successfully'
})
else:
return Response({
'message': 'Store has no warehouses'
})
else:
return Response({
'message': 'There are no saved warehouses in DB'
})
`
The 400 Error might be caused by a number of reasons. Do you have any logging information you can provide? Either from the Python logs or using the browser developer tools?
In your own code you are returning a 400 code if the variable data is empty. Are you sure you are not hitting this validation?
If nothing turns up, I advise you to add some exception dealing and logging capabilities to your own code as it seems to be very unprotected and post that information here if needed.
I have these two models: order and route. The route has a oneToMany relation with Order as you can see:
class Order(models.Model):
customer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='customer')
retailer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='retailer')
date_publish = models.DateField(default=datetime.date.today)
date_available = models.DateField()
weight = models.DecimalField(decimal_places=2, max_digits=5)
description = models.CharField(max_length=500, null=True)
route = models.ForeignKey(Route, related_name='orders', null=True, on_delete=models.CASCADE)
class Route(models.Model):
day = models.DateField()
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
start_time = models.TimeField()
When a route is created I want to associate orders with that route, so I've done the following serializer:
class routeSerializer(serializers.ModelSerializer):
orders = OrderSerializer(many=True)
class Meta:
model = Route
fields = ['day', 'warehouse', 'start_time', 'orders']
def create(self, validated_data):
orders_data = validated_data.pop('orders')
route = Route.objects.create(**validated_data)
for order_data in orders_data:
order_serializer = OrderSerializer(data=order_data)
order_serializer.is_valid(raise_exception=True)
orders = order_serializer.save()
orders.route = route
orders.save()
return route
class OrderSerializer(serializers.ModelSerializer):
ordertimelocation = orderTimelocationSerializer(many=True)
class Meta:
model = Order
fields = ['id', 'customer', 'retailer', 'date_available', 'weight', 'description', 'ordertimelocation']
def create(self, validated_data):
timelocations_data = validated_data.pop('ordertimelocation')
order = Order.objects.create(**validated_data)
for timelocation_data in timelocations_data:
order_time_location_serializer = orderTimelocationSerializer(data=timelocation_data)
order_time_location_serializer.is_valid(raise_exception=True)
order_time_location = order_time_location_serializer.save()
order_time_location.order = order
order_time_location.save()
return order
def update(self, instance, validated_data):
timelocations_data = validated_data.pop('ordertimelocation')
ordertimelocation = instance.ordertimelocation
for timelocation_data in timelocations_data:
order_time_location_serializer = orderTimelocationSerializer(data=timelocation_data)
order_time_location_serializer.is_valid(raise_exception=True)
order_time_location = order_time_location_serializer.save()
order_time_location.order = instance
order_time_location.save()
return instance
Views:
class GetRoutes(generics.ListAPIView):
queryset = Route.objects.all()
serializer_class = routeSerializer
class CreateRoute(generics.CreateAPIView):
queryset = Route.objects.all()
serializer_class = routeSerializer
class CreateOrder(generics.CreateAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class GetOrders(generics.ListAPIView):
serializer_class = OrderSerializer
def get_queryset(self):
us = self.kwargs.get('us')
return Order.objects.filter(customer_id=us)
class GetOrder(generics.RetrieveAPIView):
serializer_class = OrderSerializer
def get_object(self, queryset=None, **kwargs):
item = self.kwargs.get('order')
return get_object_or_404(Order, id=item)
class UpdateOrder(generics.UpdateAPIView):
serializer_class = OrderSerializer
queryset = Order.objects.all()
Edit:
I also customised the default user model like this:
User models:
class UserManager(BaseUserManager):
def create_superuser(self, email, user_name, first_name, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
if other_fields.get('is_staff') is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if other_fields.get('is_superuser') is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
return self.create_user(email, user_name, first_name, password, **other_fields)
def create_user(self, email, user_name, first_name, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, user_name=user_name, first_name=first_name, **other_fields)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
GENDER_MALE = 0
GENDER_FEMALE = 1
GENDER_OTHER = 2
GENDER_CHOICES = [(GENDER_MALE, 'Male'), (GENDER_FEMALE, 'Female'), (GENDER_OTHER, 'Other')]
email = models.EmailField(_('email address'), unique=True)
user_name = models.CharField(max_length=150, unique=True)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
start_date = models.DateTimeField(default=timezone.now)
is_staff = models.BooleanField(default=False)
is_retailer = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
gender = models.IntegerField(choices=GENDER_CHOICES)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['user_name', 'first_name']
def __str__(self):
return self.user_name
def isretailer(self):
return self.is_retailer
User serizalizer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'user_name', 'first_name', 'last_name')
Views:
class CustomUserCreate(APIView):
permission_classes = [AllowAny] #when a user create an account he isn't autenticated
def post(self, request, format='json'):
serializer = RegisterUserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ListUsers(generics.ListAPIView):
serializer_class = UserSerializer
queryset = User.objects.all()
class UserDetail(generics.RetrieveAPIView):
serializer_class = UserSerializer
def get_object(self, queryset=None, **kwargs):
item = self.kwargs.get('id')
return get_object_or_404(User, id=item)
I am sending a request like this:
{
"day" : "2021-12-12",
"warehouse": "1",
"start_time": "7:00",
"orders": [
{
"id": 15,
"customer": 1,
"retailer": 2,
"date_available": "2020-12-12",
"weight": "1.20",
"description": null,
"ordertimelocation": [
{
"longitude": "12.1223000000000000",
"latitude": "12.1223000000000000",
"time_interval": [
{
"start": "2021-07-21T10:10:00Z",
"end": "2021-07-21T10:10:00Z"
}
]
}
]
}
]
}
But the server returns a bad request:
{
"customer": [
"Incorrect type. Expected pk value, received User."
],
"retailer": [
"Incorrect type. Expected pk value, received User."
]
}
I'm new to django and I don't know what is a 'pk' value and why it is expecting it instead of User.
PK is primary key and in here is equal to id
For saving a record in db with it's relations, django needs PK of related object
But when you pass this pk to serializer, in validate() function of serializer, django if passed pk is existed in db and valid, if so, it would return it's model object
for example, you pass customer pk as 1, but after validation, there is a Customer object with id 1. and you are passing this object to order = Order.objects.create(**validated_data) but as i mentioned before, you should pass just PK
So one of solutions can be:
validated_data['customer'] = validated_data['customer'].id
validated_data['retailer'] = validated_data['retailer'].id
order = Order.objects.create(**validated_data)
And another solution is to overriding validate() function and control what to return
I am learning DRF and I've now run into a problem that has stalled me for days. The app is a zumba class application and I'm using DRF to create an API on top of it. The part I am trying to build right now is the part where a user can add himself to a zumba class(so, he has to be able to update a manytomany field) What I'd like the API to do when the user register himself to the class(PUT, or PATCH), is to take his username, that we get from the authentication, and add him to "myusers" field. But since the PUT is empty, the API keeps complaining that "myusers" is required.
Is there a way to tell the API that "myusers" is not required in the PUT request since it is extracted from the authentication token? (If I manually create a PUT request with "myusers": [{"id": 9}] in the body, it works but I'd like to avoid adding that client side since the data passed is not even used.)
The serializer(all the reado-only fields are to make sure the user cannot update them):
class UserActivityClassesSerializer(serializers.ModelSerializer):
activitytypename = serializers.SlugRelatedField(source='activitytype', slug_field='name', read_only=True)
activitytype = ActivityTypeSerializer(read_only=True)
myusers = MyUsersSerializer(many=True) # serializers.HyperlinkedRelatedField(many=True, view_name='myusers-detail', read_only=True)
uri = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Activity
fields = [
'uri',
'id',
'name',
'date',
'activitytype',
'activitytypename',
'status',
'myusers',
]
read_only_fields = [
'uri',
'id',
'name',
'date',
'activitytype',
'activitytypename',
'status',
]
def get_uri(self, obj):
request = self.context.get('request')
return api_reverse("api-activities:classes-detail", kwargs={"id": obj.id}, request=request)
The view
class ActivityViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated]
queryset = Activity.objects.all()
lookup_field = 'id'
def get_serializer_class(self):
if self.request.user.is_staff or self.action == 'create':
return AdminActivityClassesSerializer
else:
return UserActivityClassesSerializer
def perform_update(self, serializer):
instance = self.get_object()
request = serializer.context['request']
auth_user = request.user
qs = instance.myusers.filter(id=auth_user.id)#we verify is the user is already registered, and if yes, we remove him
if qs:
print('delete')
instance.myusers.remove(auth_user)
return instance
else:
result = verify_valid_season_pass(auth_user, instance)
if result == 1:
print('add')
instance.myusers.add(auth_user.id)
else:
raise serializers.ValidationError("No valid seasonpass found.")
The model that gets updated:
class Activity(models.Model):
CLOSE = 0
OPEN = 1
ACTIVITY_STATUS_CHOICES = [
(CLOSE, 'Closed'),
(OPEN, 'Open'),
]
name = models.CharField('Activity Name', max_length=64, blank=False, null=False)
date = models.DateTimeField('Start Date & Time', blank=False, null=False)
activitytype = models.ForeignKey(ActivityType, blank=False, null=False, default=1, on_delete=models.DO_NOTHING)
status = models.IntegerField('Status', choices=ACTIVITY_STATUS_CHOICES, default=OPEN,) # 1 = open, 0 = closed
myusers = models.ManyToManyField("users.User")
def __str__(self):
return self.name
Any clues?
Have you tried
myusers = MyUsersSerializer(many=True, required=False)
I have two models that are related to each other with user_id, now I want to have a get request in which I will have fields from both the tables. How to make this possible? I guess it would be possible with foreign key, but how do I implement it.
Two models look like:
model1
class Account(AbstractBaseUser):
fullname = models.CharField(max_length=100, blank=True)
username = models.CharField(unique=True, max_length=50)
email = models.EmailField(unique=True)
phonenumber = models.IntegerField(null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
is_admin = models.BooleanField(default=False)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
models2
class Profile(models.Model):
User = get_user_model()
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=False,
null=True
)
I want to display particular user details based on who is logged in at the moment.
My get request looks something like this:
def get(self, request, format=None):
current_user = request.user
acc = Account.objects.filter(pk=current_user.pk)
serializer = AccountSerializer(acc, many=True)
return Response(serializer.data)
But this will show only data as of Account model, I want data of Profile model too. How do I do it?
Update
serializers
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
return Account.objects.create_user(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.username = validated_data.get('username',
instance.username)
instance.fullname = validated_data.get('fullname',
instance.fullname)
password = validated_data.get('password', None)
instance.save()
return instance
Update2
After having a get requst I want something like:
{
"username": "Steve"
"fullname": "Steve Smith"
"phonenumber": "1234567890"
"email": "st#gmail.com"
"profile":[ {
"branch": "CS"
"year": 4
"image": path/to/folder
}]
}
class ProfileSerializer(ModelSerializer):
user = AccountSerializer(read_only=True)
class Meta:
model = Profile
fields = '__all__'
def get(self, request, format=None):
try:
profile= Profile.objects.get(user=request.user)
except Profile.DoseNotExist:
return Response('404')
serializer = ProfileSerializer(profile)
return Response(serializer.data)
this will return data like:
{
"your profile fields": "xxx"
...
"user": {
"your user fields": "xxx"
...
}
}
if you want your user info include profile info:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = serializers.SerializerMethodField()
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
...
def update(self, instance, validated_data):
...
def get_profile(self, instance):
try:
profile= Profile.objects.get(user=instance)
return ProfileSerializer(profile).data
except Profile.DoseNotExist:
return ''
or:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = serializers.ProfileSerializer(read_only=True)
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
...
def update(self, instance, validated_data):
...
this will return:
{
"username": "Steve"
"fullname": "Steve Smith"
"phonenumber": "1234567890"
"email": "st#gmail.com"
"profile":{
"branch": "CS"
"year": 4
"image": path/to/folder
}
}
as your profile is onetoone to user,so profile is JsonObject not JsonArray
Configure your AccountSerializer somewhat like this,
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = [f.name for f in model._meta.fields]
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = ProfileSerializer()
class Meta:
model = Account
fields = [f.name for f in model._meta.fields]
You may also override your create and update methods of your serializer accordingly.
I'm a little new to Django and Django-REST so please bear with me. Perhaps the answer is in the documentation, so if I missed it, apologies in advance.
Goal: I would like to create an EquipmentInfo object whose attributes include pre-existing foreign keys (EquipmentType and EquipmentManufacturer).
models.py
class EquipmentType(models.Model):
equipment_type = models.CharField(verbose_name="Equipment Type", max_length=50, unique=True)
def __unicode__(self):
return self.equipment_type
class EquipmentManufacturer(models.Model):
manufacturer_name = models.CharField(verbose_name="Manufacturer Name", max_length=50, unique=True)
def __unicode__(self):
return self.manufacturer_name
class EquipmentInfo(models.Model):
equipment_type = models.ForeignKey(EquipmentType, verbose_name="Equipment Type")
part_identifier = models.CharField(verbose_name="Machine ID (alias)", max_length=25)
manufacturer_name = models.ForeignKey(EquipmentManufacturer, verbose_name="Manufacturer Name")
serial_number = models.CharField(verbose_name="Serial Number", max_length=25)
date_of_manufacture = models.DateField(verbose_name="Date of Manufacture", default=date.today)
is_active = models.BooleanField(verbose_name="Is Active", default=True)
def __unicode__(self):
return self.part_identifier
serializers.py
class EquipmentTypeSerializer(serializers.ModelSerializer):
class Meta:
model = EquipmentType
fields = ('id', 'equipment_type',)
class EquipmentManufacturerSerializer(serializers.ModelSerializer):
class Meta:
model = EquipmentManufacturer
fields = ('id', 'manufacturer_name',)
class EquipmentInfoSerializer(serializers.ModelSerializer):
class Meta:
model = EquipmentInfo
fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')
equipment_type = EquipmentTypeSerializer(many=False)
manufacturer_name = EquipmentManufacturerSerializer(many=False)
def create(self, validated_data):
equipment_type = validated_data.pop('equipment_type')
manufacturer_name = validated_data.pop('manufacturer_name')
equipment_info = EquipmentInfo.objects.create(**validated_data)
return equipment_info
Assuming I already have relevant EquipmentType and EquipmentManufacturer objects created, I would like to add another EquipmentInfo object. What is the appropriate way to set up my EquipmentInfo serializer so that I can pass in information such as
{
"equipment_type":{
"equipment_type":"already_created",
},
"part_identifier":"something_new",
"manufacturer_name":{
"manufacturer_name":"already_created"
},
"serial_number":"WBA1",
"date_of_manufacture": "1900-01-01",
"is_active":true
}
or even better:
{
"equipment_type":"already_created",
"part_identifier":"something_new",
"manufacturer_name":"already_created",
"serial_number":"WBA1",
"date_of_manufacture": "1900-01-01",
"is_active":true
}
Any help is appreciated.
I have also faced the problem ,and have solved it ,the following is my step ,hope it will be helpful
1.company Model and contact model as follows:
class Company(models.Model):
Company_Name = models.CharField(u'Company Name',max_length=255, default="")
Modified_By = models.CharField(u'Modified By',max_length=255, default="")
class Company_Contact(models.Model):
Company = models.ForeignKey(Company)
Last_Name = models.CharField(u'Last Name',max_length=255, default="")
First_Name = models.CharField(u'First Name',max_length=255, default="")
2.I create A New Serializer Named CompanyReferenceSerializer,and company_contact
class CompanyReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ['id', 'Company_Name', 'Company_Name_SC']
class CompanyContactSerializer(serializers.ModelSerializer):
Company = CompanyReferenceSerializer()
class Meta:
model = Company_Contact
fields = ['Company', 'Last_Name','First_Name']
extra_kwargs = {
'Company': {'allow_null': True, 'required': False},
'Last_Name': {'allow_null': True, 'allow_blank': True, 'required': False},
'First_Name': {'allow_null': True, 'required': False, 'allow_blank': True},
}
3.Viewset as follows,in the backend,I get the object Namedcompany_instanceaccording to the 'company_id'
class CompanyContactViewSet(viewsets.ModelViewSet):
serializer_class = CompanyContactSerializer
def create(self, validated_data):
serializer = self.get_serializer(data=self.request.data)
company_id_for_contact = self.request.data.pop('Company_id')
company_instance = Company.objects.filter(id=company_id_for_contact).first()
if not serializer.is_valid():
print serializer.errors
data = serializer.validated_data
serializer.save(Company=company_instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
and I success insert one record in the company_contact ,Hope it can help you !
Using nested serializers makes it really hard for posts (if it even works, as it didn't used to work), and given your simple models, I would recommend just removing them.
I will recommend you add APIs for
/api/v1/type
/api/v1/manufacturer
/api/v1/info
(or whatever names you want to use). The type and manufacturer ones should be vanilla views and using your existing serializers.
For info, remove the two nested serializers:
class EquipmentInfoSerializer(serializers.ModelSerializer):
class Meta:
model = EquipmentInfo
fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')
After that, you should be able to do post using:
data = {
"equipment_type": 5, # The ID of the equipment type record
"part_identifier":"something_new",
"manufacturer_name": 10 # The ID of the manufacturer record
"serial_number":"WBA1",
"date_of_manufacture": "1900-01-01",
"is_active":true
}
In my case, I do like making it the GETs more convenient so I add read-only fields to return a name (or even the whole serialized record):
class EquipmentInfoSerializer(serializers.ModelSerializer):
type_name = serializers.SerializerMethodField(read_only=True)
class Meta:
model = EquipmentInfo
fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')
def get_type_name(self, obj):
return obj.equipment_type.equipment_type
Hope this helps.