Limit Choices of Foreign Keys in DRF - django

I have model Commodity:
class Commodity(models.Model):
shop = models.ForeignKey(Shop, related_name='commodity', on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, blank=True, null=True, on_delete=models.CASCADE)
price_old = models.DecimalField(max_digits=10, decimal_places=2)
price_new = models.DecimalField(max_digits=10, decimal_places=2)
I tried to use limit_choices_to and it didn't work.
I have a Serializer:
class CommoditySerializer(serializers.ModelSerializer):
image = CommodityImageSerializer(many=False)
def get_queryset(self):
user = self.context['request'].user
queryset = Commodity.objects.filter(shop__company__user=user)
return queryset
class Meta:
model = Commodity
fields = ('id', 'shop', 'brand', 'price_old', 'price_new')
This get_queryset also dont help me.
Finally I have a regular CreateAPIView, and this method also dont help me.
How can I limit usage of foreign keys? I need to let create commodities to my user only within user's Shops. THanks!

I suppose you can simply implement validate_shop method for this:
class CommoditySerializer(serializers.ModelSerializer):
image = CommodityImageSerializer(many=False)
def validate_shop(self, value):
user = self.context['request'].user
if value.company.user == user:
return value
raise serializers.ValidationError('Invalid shop!')
class Meta:
model = Commodity
fields = ('id', 'shop', 'brand', 'price_old', 'price_new')

Related

How to retrieve data from model that current user created and list it for another model's field in django

Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\

AttributeError at /api/module/list/

I want many to many fields to be displayed in module serializer instead of id, these are my serializers
class TrainerSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', ]
class ModuleSerializer(serializers.ModelSerializer):
trainer = serializers.CharField(source='trainer.username')
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer',
'publish_choice']
class Trainer(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
def __str__(self):
return str(self.user)
class Meta:
ordering = ['pk']
class Module(models.Model):
title = models.CharField(max_length=80, unique=True)
duration = models.IntegerField(verbose_name='Duration in Days/ Weeks', blank=True, null=True)
trainer = models.ManyToManyField(Trainer, blank=True)
detail = models.TextField(verbose_name='Program Details', blank=True, null=True)
notify = models.BooleanField(default=False)
publish_choice = models.CharField(verbose_name='Publish/ Draft',
max_length=80, choices=PUBLISH_CHOICES, default='publish')
and this is the error message
Got AttributeError when attempting to get a value for field trainer on serializer ModuleSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Module instance.
Original exception text was: 'ManyRelatedManager' object has no attribute 'username'.
We have a depth parameter in the serializer MetaClass. we can make use of it like below. depth=1 will retrieve all fields of a relation.
class ModuleSerializer(serializers.ModelSerializer):
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer', 'publish_choice']
depth = 1
for reference DRF-Documentation on serializers
Its raise exception because serializers.CharField(source='trainer.username') not match ManyRelatedManager in model trainer = models.ManyToManyField(Trainer, blank=True).
If you want get all username instead of id, you can try add Custom type serialzier like this:
class ModuleSerializer(serializers.ModelSerializer):
trainer = serializers.SerializerMethodField()
def get_trainer(self, obj):
results = []
for item in obj.trainers.all():
results.append(item.username)
return results
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer', 'publish_choice']
trainer will return array of username relation with Module

Django, DRF (& React) Foreign key, how to display the name value instead of the foreign key id

There are two Django models - ClientCompany & Proposal and the foreign key of ClientCompany is within the Proposal model. In Proposal how do I display the name of the ClientCompany instead of the foreign key id?
models.py:
class ClientCompany(models.Model):
name = models.CharField("Client Name", max_length=255)
abn_acn = models.BigIntegerField("ABN / ACN")
def __str__(self):
return self.name
class Proposal(models.Model):
proj_name = models.CharField("Project Name", max_length=255)
loc_state = models.CharField(
max_length=3,
)
proj_type = models.CharField(
max_length=30,
)
prop_status = models.CharField(
max_length=20,
)
client = models.ForeignKey(ClientCompany, on_delete=models.CASCADE)
oneic = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='main_engineer')
twoic = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='second_engineer')
created_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.proj_name
serializers.py:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = ClientCompany
fields = ('id', 'name', 'abn_acn')
class ProposalSerializer(serializers.ModelSerializer):
class Meta:
model = Proposal
fields = ('id', 'proj_name', 'loc_state', 'proj_type', 'prop_status', 'client', 'oneic', 'twoic',)
queryset api.py:
class ProposalViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, ]
queryset = Proposal.objects.all()
serializer_class = ProposalSerializer
currentlyshows the client foreign key id
I've been stuck on this, tried to apply the existing solutions recommended for similar problems but had no luck... if someone can tell me what I'm missing - thanks
I found this worked in the end by adding the serializers.SlugRelatedField line in serializers.py:
class ProposalSerializer(serializers.ModelSerializer):
client = serializers.SlugRelatedField(slug_field="name", read_only=True)
class Meta:
model = Proposal
fields = ('id', 'proj_name', 'loc_state', 'proj_type', 'prop_status',
'client', 'oneic', 'twoic',)
Update your serializer like this:
class ProposalSerializer(serializers.ModelSerializer):
client = ClientSerializer()
class Meta:
model = Proposal
fields = ('id', 'proj_name', 'loc_state', 'proj_type', 'prop_status', 'client', 'oneic', 'twoic',)

related objects queries django rest framework

I have the following models
class STUser(AbstractBaseUser):
email = models.EmailField(unique=True)
name = models.CharField(max_length=255)
companyname = models.CharField(max_length=200, blank=True, null=True)
...
class VenuePermissions(models.Model):
user = models.ForeignKey(STUser, on_delete=models.CASCADE)
venue = models.ForeignKey(Venue, on_delete=models.CASCADE)
signupvaildatestring = models.CharField(max_length=200, blank=True, null=True)
...
I want to grab all the STUser objects and grab all their permissions.
So what I would like is to grab all the VenuePermissions objects. And grab the user and venue object of each venuePermission
Two ways I can do this. use the VenuePermissions_set attribute on STUser but then how do I grab the venue when its just going to be a pk value?
Or focus on the VenuePermissions objects and grab the user and venue from the pk values but how?
I remember nested queries, and I kinda did one in my browse code.
here is an example:
rooms = Room.objects.filter(venue=OuterRef('pk'), sixtyroundseatingoption= True)
venuelist = venuelist.annotate(sixtyrounds=Exists(rooms))
venuelist = venuelist.filter(Q(sixtyrounds = True) | Q(fullbuyoutsixtyroundseatingoption = True))
I've done the set objects in a serializer before
Example serializer:
class RoomAndImageSerializer(serializers.ModelSerializer):
roomimage_set = RoomImageSerializer(many=True, read_only=True)
class Meta:
model = Room
fields = ('pk','name')
any help with this query would be appreciated!
So this is what I am currently trying, I will post an answer if this works:
class VenueUserList(ListAPIView):
serializer_class = VenueUserListSerializer
queryset = VenuePermissions.objects.select_related('user').select_related('venue').filter(signupvaildatestring=None)
class VenueUserListSerializer(serializers.ModelSerializer):
user = UserSerializer()
venue = VenueSerializer()
class Meta:
model = VenuePermissions
fields = ('user', 'venue', 'isvenueviewer', 'isvenueeventplanner', 'isvenueadministrator')
Here is the answer. However I still need to group venues by user. Working on that.
class VenueUserList(ListAPIView):
serializer_class = VenueUserListSerializer
queryset = VenuePermissions.objects.select_related('user').select_related('venue').filter(signupvaildatestring=None)
class VenueUserListSerializer(serializers.ModelSerializer):
user = UserSerializer()
venue = VenueSerializer()
class Meta:
model = VenuePermissions
fields = ('user', 'venue', 'isvenueviewer', 'isvenueeventplanner', 'isvenueadministrator')

Django Rest Framework: serializing/deserializing a calculated field

I just started using Django & Django REST framework. I have the following models:
class Account(models.Model):
name = models.CharField(max_length=100, blank=False)
vat_perc = models.DecimalField(max_digits=4, decimal_places=2)
def __str__(self):
return "ACCOUNT: {0} -- {1}".format(self.name, str(self.vat_perc))
class Entry(models.Model):
account = models.ForeignKey(Account)
description = models.CharField(max_length=100)
taxable_income = models.DecimalField(max_digits=10, decimal_places=2)
total_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True)
def save(self, *args, **kwargs):
selected_vat = Account.objects.get(pk=self.account).vat_perc
self.total_amount = self.taxable_income * (100.00+selected_vat)/100.00
super(Entry, self).save(*args, **kwargs)
The idea would be to read the vat_perc value inside the account record the user has just selected and to perform a calculation to determine the total_amount value which then should be saved in the entry record on the database (I know some would regard this as suboptimal due to the duplication of data in the database; please follow me anyway).
The total_amount field should be regularly serialized when requested. Instead, the serializer should not do anything for deserialization, because the overriding of the save method in the model takes care of updating values if a creation or modification occurs. If I get the documentation correctly, all this means setting the total_amount field in the serializer class as read_only.
Now, these are my serializers:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'name', 'vat_perc',)
class EntrySerializer(serializers.ModelSerializer):
class Meta:
model = Entry
fields = ('id', 'account', 'description', 'taxable_income', 'total_amount',)
total_amount = serializers.ReadOnlyField()
# alternatively: total_amount = serializers.FloatField(read_only=True)
But this is the error I get:
Got a TypeError when calling Entry.objects.create(). This may be because you have a writable field on the serializer class that is not a valid argument to Entry.objects.create(). You may need to make the field read-only, or override the EntrySerializer.create() method to handle this correctly.
Original exception text was: int() argument must be a string, a bytes-like object or a number, not 'Account'.
The last sentence sounds particularly obscure to me. Am I getting something wrong? Any hint?
Thanks in advance.
Thanks to Claudiu. Used SlugRelatedField in the serializer class and decimal.Decimaltype instead of float as I did mistankenly. The following code now works:
class Account(models.Model):
name = models.CharField(max_length=100, blank=False)
vat_perc = models.DecimalField(max_digits=4, decimal_places=2)
def __str__(self):
return "ACCOUNT: {0} -- {1}".format(self.name, str(self.vat_perc))
class Entry(models.Model):
account = models.ForeignKey(Account)
description = models.CharField(max_length=100)
taxable_income = models.DecimalField(max_digits=10, decimal_places=2)
total_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True)
def save(self, *args, **kwargs):
self.total_amount = self.taxable_income * (decimal.Decimal(100.00) + self.account.vat_perc) / decimal.Decimal(100.00)
super(Entry, self).save(*args, **kwargs)
serializers.py
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'name', 'vat_perc',)
class EntrySerializer(serializers.ModelSerializer):
class Meta:
model = Entry
fields = ('id', 'account', 'description', 'taxable_income', 'total_amount',)
total_amount = serializers.ReadOnlyField()
account = serializers.SlugRelatedField(queryset=Account.objects.all(), slug_field="vat_perc")