I have user serializer in which i need to show in every user detail advertises which he published
models.py:
class Advertise(models.Model):
title = models.CharField(max_length=120)
publisher = models.ForeignKey(User, related_name='publisher',null=True, blank=True, on_delete=models.CASCADE)
category = models.CharField(choices=CATEGORIES, max_length=120)
description = models.TextField(max_length= 200, null=True, blank=True)
image = models.ImageField(upload_to='project_static/Advertise/img', null=True, blank=False)
price = models.DecimalField(decimal_places=2, max_digits=20)
timestamp = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
location = models.CharField(max_length=120 , null=True, blank=True)
contact = models.CharField(max_length=120,null=True, blank=True)
def __str__(self):
"""show ad name in admin page"""
return self.title
def get_absolute_url(self):
return reverse("advertise:advertise-detail", kwargs={"pk":self.pk})
serilaizers.py:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.CharField(source='get_absolute_url')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher = AdSerializer(source='publisher_set', many=True)
class Meta:
model = User
fields = ['id', 'username','publisher']
error:
Got AttributeError when attempting to get a value for field publisher on serializer UserSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'publisher_set'.
ok, I solved it by making some changes:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.HyperlinkedIdentityField(view_name='advertise:ad_detailview', source='Advertise')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher_of = AdSerializer(many=True)
url = serializers.HyperlinkedIdentityField(view_name='advertise:user-detail', source='User')
class Meta:
model = User
fields = ('url', 'id','username', 'email', 'publisher_of')
also in models.py publisher field got related_name="publisher_of" for more symantic
This link helped
https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/
Related
I have this model that represents a bookmark or favorite. It has multiple foreign keys to other models. In the api I would like to pull in the data from each of the models that is referenced in the particular bookmark.
The model:
class Bookmark(models.Model):
marktype = models.CharField(max_length=10)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
question = models.OneToOneField(Question, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
I tried to use a SerializerMethodField but I get an error: 'NoneType' object has no attribute 'id'
Here is the serializer
class BookmarkSerializer(serializers.ModelSerializer):
post = serializers.SerializerMethodField()
question = serializers.SerializerMethodField()
class Meta:
model = Bookmark
fields = '__all__'
def get_post(self, obj):
obj = Post.objects.get(id=obj.post.id)
post = ShortPostSerializer(obj)
return post.data
def get_question(self, obj):
obj = Question.objects.get(id=obj.question.id)
question = ShortQuestionSerializer(obj)
return question.data
what am I doing wrong please?
You can update your serializer like the following (You can short it as you want or use your ShortQuestionSerializer as well instead of QuestionSerializer),
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class BookmarkSerializer(serializers.ModelSerializer):
post = PostSerializer()
question = QuestionSerializer()
class Meta:
model = Bookmark
fields = '__all__'
The simple user must either not see the status button or it must be grayed out for selection. Admin(user.is_staff) and Support(user.is_superuser) should see the field and be able to change it.
Now user can change the status of ticket in Update view.
My serializer:
class TicketSerializerUpdate(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
status = Status.objects.all()
class Meta:
model = Ticket
fields = "__all__"
My models Ticket and Status:
class Status(models.Model):
status = models.CharField(max_length=150)
desc_status = models.TextField()
def __str__(self):
return self.status
class Ticket(models.Model):
title = models.CharField(max_length=150)
text = models.TextField()
status = models.ForeignKey(Status, on_delete=models.PROTECT, default=2)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
time_create = models.DateTimeField(auto_now_add=True)
time_update = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
File permissions now haven't anything for solve the problem and I haven't any idea. I think it is simple problem, if you need more info you can request me)
You can use different Serializers for different users in your view using get_serializer_class():
class SimpleUserSerializer(serializers.ModelSerializer):
class Meta:
model = Ticket
fields = "__all__"
read_only_fields = ('status',)
class AdminUserSerializer(serializers.ModelSerializer):
class Meta:
model = Ticket
fields = "__all__"
class ExampleView(viewsets.ModelViewSet):
...
def get_serializer_class(self):
if self.request.user.is_admin:
return AdminUserSerializer
return SimpleUserSerializer
I am trying to make a post api, where a merchant can add products by selecting category, brand, collection in a merchant dashboard. But when I try to send raw json data from the postman, it says category, brand and collection already existed.
My models:
class Seller(models.Model):
seller = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
business_name = models.CharField(max_length=50, blank=True)
phone_num = models.CharField(max_length=50, blank=True)
class Product(models.Model):
merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
category = models.ManyToManyField(Category, blank=False)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
featured = models.BooleanField(default=False)
My views:
class ProductAddAPIView(CreateAPIView):
permission_classes = [IsAuthenticated]
queryset = Product.objects.all()
serializer_class = AddProductSerializer
My serializers:
class AddProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(many=True,required=True)
brand = BrandSerializer(required=True)
collection = CollectionSerializer(required=True)
merchant = serializers.PrimaryKeyRelatedField(read_only=True)
variants = VariantSerializer(many=True,required=True)
class Meta:
model = Product
fields = ['id','merchant','category','brand', 'collection','featured', 'top_rated',
'name','description', 'picture','main_product_image','best_seller',
'rating','availability','warranty','services','variants']
# depth = 1
def create(self, validated_data):
user = self.context['request'].user
category_data = validated_data.pop('category',None)
brand_data = validated_data.pop('brand',None)
collection_data = validated_data.pop('collection',None)
product = Product.objects.create(merchant=user,**category_data,**brand_data,**collection_data)
return product
My urls:
path('api/addproducts', views.ProductAddAPIView.as_view(), name='api-addproducts'),
class AddProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(many=True,required=True)
brand = BrandSerializer(required=True)
....
The nested serializers above (like category, brand fields) are assuming that it is creating new instance/s for category & brand. Even if you pass an id because it that field is read_only by default in ModelSerializer so it never gets included in validate_data.
If the use of the serializer is only for writing, I suppose you can use PrimaryKeyRelatedField:
class AddProductSerializer(serializers.ModelSerializer):
category = serializers.PrimaryKeyRelatedField(many=True, required=True, queryset=Category.objects.all())
brand_id = serializers.PrimaryKeyRelatedField(required=True, queryset=Brand.objects.all())
class Meta:
model = Product
fields = [
# other fields here
"brand_id", # previously "brand"
]
drf docs:
https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield
I am creating sample-api which have posts and followers. Post should visible to followers only
My models.py
from django.contrib.auth.models import User
class Post(models.Model):
creator = models.ForeignKey(User, related_name='creator_post_set', null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=25)
created_date = models.DateTimeField(auto_now_add=True)
content = models.TextField()
likes = models.BigIntegerField(null=True)
comments = models.BigIntegerField(null=True)
class Follow(models.Model):
follower = models.ForeignKey(User, related_name='following', null=True, on_delete=models.CASCADE)
followed_on = models.DateTimeField(auto_now_add=True)
following = models.ForeignKey(User, related_name='follower',null=True, on_delete=models.CASCADE)
My serializers.py for the models:
class UserSerializer(ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
password=validated_data['password'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
)
return user
class Meta:
model = User
fields = ('password', 'username', 'first_name', 'last_name',)
class PostListSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['title', 'content', 'created_date',]
class FollowSerializer(serializers.ModelSerializer):
class Meta:
model = Follow
fields = '__all__'
My views.py:
class PostList(generics.ListCreateAPIView):
serializer_class = PostListSerializer
follow_model = FollowSerializer.Meta.model
post_model = PostSerializer.Meta.model
def get_queryset(self):
try:
followers = self.follow_model.objects.get(follower_id =
self.request.user.id)
queryset = self.post_model.objects.get(creator__in = followers)
except self.follow_model.DoesNotExist:
queryset = None
return queryset
When I call this view it returns the following error:
Cannot query "Follow object (1)": Must be "User" instance.
I need help Thanks in Advance.
As I can see, Post model's creator is FKed to User model. So you need to query using User model instance, not Follower model.
You can use the following code:
following = self.request.user.following.all().values_list('follower', flat=True) # because of related name
queryset = self.post_model.objects.filter(creator_id__in = list(following))
Here I have first retrieved the user ids using self.request.following.all() by reverse relationship. Then I have extracted the user ids using values_list. After that, I have used it in Post.objects.filter(...) method.
I have a django model named Event, which references Customer model.
event_name = models.CharField(max_length=200, unique=True)
customer = models.ForeignKey(customer_models.Customer, db_index=True,
on_delete=models.SET_NULL,
related_name='customer_events', null=True)
event_location = models.CharField(max_length=200, default='')
event_date = models.DateField()
I need to get the customer list along with the latest event name for each user in the API.
Customer serializers.py file is
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
Customer views.py file is
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
How can I accomplish this?
In your Customer model you can have a property that returns the latest event name for a Customer instance:
class Customer(models.Model):
...
#property
def latest_event_name(self):
"""Return latest event name."""
# self.customer_events.order_by('event_date').last()
latest_event = self.customer_events.order_by('-event_date').first()
return latest_event.event_name if latest_event else None
In your serializer you can then add a ReadOnlyField for latest_event_name:
class CustomerSerializer(serializers.ModelSerializer):
latest_event_name = serializers.ReadOnlyField()
class Meta:
model = Customer
fields = '__all__'