Error with Nested Serializer - django-rest-framework

I have the following model and serializer:
class SeminarTracking(models.Model):
id = models.BigIntegerField(primary_key=True)
id_tax_seminar = models.BigIntegerField(null=True, blank=True)
cid = models.ForeignKey('clients.Client')
invite = models.IntegerField(null=True, blank=True)
invite_2 = models.IntegerField(null=True, blank=True)
rsvp = models.CharField(max_length=255L, blank=True)
attendees = models.IntegerField(null=True, blank=True)
names = models.CharField(max_length=255L, blank=True)
notes = models.TextField(blank=True)
class Meta:
db_table = 'tax_seminars_tracking'
class SeminarTrackingSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = SeminarTracking
Client serialize:
class ClientSerializer(serializers.HyperlinkedModelSerializer):
#adwebsite = serializers.PrimaryKeyRelatedField()
#adissue = serializers.PrimaryKeyRelatedField(required=False)
#category = serializers.PrimaryKeyRelatedField(many=True)
status = serializers.Field()
seminars = SeminarTrackingSerializer(source='seminartracking_set')
class Meta:
model = Client
Whenever I access the client via the API, I get the following error:
(1054, "Unknown column 'tax_seminars_tracking.cid_id' in 'field list'")
If I access seminartracking_set in a view or template, it works no problems. Is there something I am missing? - Note the primary key of the client model is clientid, not id - not sure if that's relevant.
Many thanks, Ben

I had to specify the column name on the "cid" feild.

Related

DRF read_only fields not being ignored when saving

I am using Django 2.2.23 and Django Rest Framework 3.7.7. I have models and serialisers as follows:
class PurchaseOrder(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
order_number = models.IntegerField(null=True, blank=True)
contact = models.ForeignKey(SupplierContact, on_delete=models.SET_NULL, null=True)
class SupplierContact(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=100, null=True, blank=True)
class PurchaseOrderSerializer(serializers.ModelSerializer):
contact_name = serializers.CharField(read_only=True, source='contact.name', default='')
class Meta:
model = PurchaseOrder
fields = ['uid', 'order_number', 'contact_name']
Doing
serializer = PurchaseOrderSerializer({'order_number': 1234})
serializer.save()
results in *** ValueError: Cannot assign "{'name': ''}": "PurchaseOrder.contact" must be a "SupplierContact" instance.
where I would've thought the read_only=True on the contact_name field would exclude it from saving. What am I missing?

DRF - Add User to a model with ManyToManyField

I am trying to implement a feature to my backend and allow the owner of private "Group" to add other users by their usernames instead of ID's and allow them to add their images to FileField only once after they were added to the model. The code I have so far:
models.py
class Group(models.Model):
group_name = models.CharField(max_length=255)
group_text = models.TextField(max_length=360, blank=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='owner_user', on_delete=models.SET(get_deleted_user), default=1)
created_on = models.DateTimeField(auto_now_add=True, null=True)
shared_to = models.ManyToManyField(UserProfile, blank=True, related_name='shared_to_user', null=True)
def __str__(self):
return self.group_name
def save(self, *args, **kwargs):
super(Group, self).save(*args, **kwargs)
class GroupImage(models.Model):
group_file = models.FileField(blank=True, null=True,
upload_to='media/covers/%Y/%m/%D/')
gallery_group = models.ForeignKey(Group, related_name='images', on_delete=models.CASCADE)
serializers.py
class GroupImageSerializer(serializers.ModelSerializer):
class Meta:
model = models.GroupImage
fields = ('group_file', )
class SharedToSerializer(serializers.ModelSerializer):
class Meta:
model = models.Group
fields = ('shared_to', )
class GroupSerializer(serializers.ModelSerializer):
images = GroupImageSerializer(many=True, read_only=True)
person = SharedToSerializer(many=True, read_only=True)
class Meta:
model = models.Group
fields = ('id', 'group_name', 'group_text', 'person', 'images')
def create(self, validated_data):
images_data = self.context.get('view').request.FILES
owner_id = self.context['request'].user.id
gallery_group = models.Group.objects.create(group_name=validated_data.get('group_name', 'no-
group_name'), group_text=validated_data.get('group_text'), owner_id=1)
for image_data in images_data.values():
models.GroupImage.objects.create(gallery_group=gallery_group,
group_file=image_data)
return gallery_group
views.py
class GroupCreateAPIView(generics.CreateAPIView):
queryset = models.Group.objects.all()
serializer_class = serializers.GroupSerializer
permission_classes = [AllowAny]
So if your only requirement is how to add users by their username and not their id. You should use SlugRelatedField. I also feel your serializer naming convention is quite confusing. Below is the serializer for Group model that can add users to a group.
class GroupSerializer(Serializer):
... other fields here
shared_to = models.SlugRelatedField(queryset = UserProfile.objects.all(), many=True, slug_field="username", allow_empty=True)
So first checkout SlugRelatedField. This basically is used to map to objects using a specific field of that object(username in this case). You will then get all the UserProfile instances in the shared_to field of the validated_data
property of the serializer which you can fetch in create method and add to you group. And then in the file upload api for your group you can check whether this user belongs to the group or not for permission checking.

Saving(create,update) along with foreignkey value from another model which is related user model

It may be a challenging question if you didn't get rightly. Here I have three models in which department model should be created by taking its place name from Place model which is related to the staff model. The Staff Model is in a OneToOneField relationship with User, so when a user creates a department the place name should be passed like HiddenField in HTML . This place name is related to place model with the user with GenericForeignKey. i have created a serializer which is not working as expected, it is returning the place name ,
.
In shortly I want to create a department while place should be selected from current user ID
class Staff(BaseModel):
ROLES = [
('ADMIN', 'Admin'),
('TEACHER', 'Teacher')
]
auth_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
school_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
school_id = models.PositiveIntegerField()
school = GenericForeignKey('school_content_type', 'school_id')
role = models.CharField(null=True, blank=True, choices=ROLES, max_length=20)
class Places(BaseModel):
name = models.CharField(max_length=50)
code = models.CharField(max_length=12, unique=True)
class Department(BaseModel):
TYPES = [
('ONLINE', 'Online'),
('OFFLINE', 'OfFline')
]
department_type = models.CharField(max_length=15, choices=TYPES)
service_no = models.CharField(max_length=50)
instructions = models.TextField(null=True, blank=True)
place = models.ForeignKey(Places, to_field='code', db_column='place_code', on_delete=models.PROTECT)
SERIALIZERS
class DepartmentCreateSerializer(serializers.ModelSerializer):
place_code=serializers.CharField(read_only=True)
class Meta:
model=Department
fields = ('department_type','service_no','instructions')
def get_place(self, request):
user_id=self.context['request'].user.id
school_id=Staff.objects.get(auth_user_id= user_id).school_id
places_code_name=Places.objects.get(id= school_id).name
class PlacesSerializer(serializers.ModelSerializer):
class Meta:
model = Places
fields = ('id', 'code', 'name')
from places.serializers import PlacesSerializer
class DepartmentCreateSerializer(serializers.ModelSerializer):
place= PlacesSerializer(read_only=True)
class Meta:
model=Department
fields = ('place','service_no','instructions')
def validate(self, attrs):
palce_obj = self.context['request'].user.staff.place()
attrs.update({'place': place_obj})
attrs = super().validate(attrs)
if not attrs.get('place', None):
raise serializers.ValidationError({'place': ["Place required"]})
return attrs

Django DRF serializer - inserting data containing foreign key relationships

I have the following models:
class Contact(models.Model):
class Meta:
managed = False
db_table = 'contact'
class ContactPhone(models.Model):
contact = models.ForeignKey(Contact, on_delete = models.CASCADE)
number = models.CharField(max_length = 45)
class Meta:
managed = False
db_table = 'contact_phone'
Also, I have the following serializers:
class ContactSerializer(serializers.ModelSerializer):
server_id = serializers.IntegerField(source='id', read_only=True)
class Meta:
model = Contact
fields = '__all__'
class ContactPhoneSerializer(serializers.ModelSerializer):
class Meta:
model = ContactPhone
fields = '__all__'
Now, I have a view that insert phone numbers for an existing contact.
The input is a json that looks like this:
data = {'contact_id': 12322,
'phones':[{'number': '89120000001'}]}
The view:
def insert_contact_phone(request):
for record in request.data['phones']:
data['contact_id'] = request.data['contact_id']
serializer = ContactPhoneSerializer(data = data)
if serializer.is_valid():
serializer.save()
I end up with the following error:
RelatedObjectDoesNotExist at /contacts/edit ContactPhone has no
contact.
What am I doing wrong?
If you specify __all__ for the fields in your ContactPhoneSerializer, it does not include contact_id.
So the contact_id taken from the json input is not serialized. It is basically ignored and when you try to save and create new ContactPhone - it fails, because it does not have contact's foreign key correctly set.
But simply adding contact_id to the serializer's fields won't solve your problem.
In your view, i recommend you to set the contact instead:
data['contact'] = request.data['contact_id']
and pass this to the ContactPhoneSerializer.

DRF - html post options only for user logged in

I have the following serializer:
class WidgetSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model=Widget
fields = ('id', 'title', 'description', 'username', 'code', 'owner', 'list')
The problem is that the 'list' field, which is a drop down, gives all lists whereas I only want it to display lists that are owned by the user currently logged in.
Here's the respective models:
class WidgetList(MPTTModel):
name = models.CharField(max_length=100)
description = models.CharField(max_length=1024)
owner = models.ForeignKey('MyUser')
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
def __str__(self):
return self.name
class MPTTMEta:
order_insertion_by = ['name']
class Widget(models.Model):
title = models.CharField(max_length=100)
description = models.CharField(max_length=1024)
username = models.CharField(max_length=50)
code = models.CharField(max_length=1024)
owner = models.ForeignKey('MyUser', related_name='MyUser_owner')
list = models.ForeignKey('WidgetList')
I am a beginner in django. I hope that I could help.
Just try this
WidgetList.objects.filter(owner=request.user)
I have to limit it through a SlugRelatedField as per the documentation here -
http://www.django-rest-framework.org/api-guide/relations/#slugrelatedfield
I then used it like so -
list = serializers.SlugRelatedField(
queryset=WidgetList.objects.filter(owner=3),
many=True,
slug_field='name'
)
All I need to figure out now is to pass the serializers.CurrentUserDefault() in the filter for the queryset, or pass request.user.

Resources