how to get the objects of specific field - django

Tn the following code the User.objects returns the "url","username","email","groups"
from django.contrib.auth.models import User, Group
class UserViewSet(viewsets.ModelViewSet):
# TODO return only usernames and urls without emails for privacy purpeses
# User.objects.username
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
But I also create the following model for the user avatar
class TheUserProfiel(models.Model):
TheUser = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(blank=True, null=True)
personalityInformation = models.CharField(
max_length=9999999, null=True, blank=True)
created_date = models.DateTimeField(default=timezone.now)
So, HOW to make the UserViewSet to return all of these "url","username","email","groups" in addition to the "avatar" field in the same view
I tried before to create two views and to combine them in the frontend but it got very complicated.

You can achieve this simply by updating the UserSerializer
serializer_class = UserSerializer
In the serializers, you had define UserSerializer. In that serializer update the fields attribute of meta class to include avatar.
UserSerializer(...):
...
class Meta:
...
fields = (....., 'avatar')

Related

making an API that adds instances to ManyToMany fields of a model in django rest framework

I am making a movie watching website in which there are users and films and the user model has a ManyToMany Field that references the film model. it's called WatchList and an authenticated user can add any movie they want to this watchlist.
My problem is that I want an API that only gets the ID of a film and adds it to the user's watch list.
these are my models and serializers and I am trying to make a view to implement this API.
# models.py
class Film(models.Model):
filmID = models.AutoField(primary_key=True)
title = models.CharField(max_length=150)
# ...
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
watchList = models.ManyToManyField(Film)
objects = UserManager()
USERNAME_FIELD = 'username'
# serializers.py
class WatchListSerializer(serializers.ModelSerializer):
class FilmSerializer(serializers.ModelSerializer):
model = Film
fields = ('filmID', 'title',)
read_only_fields = ('filmID', 'title')
film_set = FilmSerializer(read_only=True, many=True)
class Meta:
model = get_user_model()
fields = ('userID', 'film_set')
read_only_fields = ('userID',)
# views.py
class WatchListAddView(...):
pass
The serializer can be changed. but this kind of shows what I want the api to be. the authentication validation part is already taken care of, so imagine that any request to the view is from an authenticated user.
I would not recommend patching this directly and instead create a separate endpoint for adding removing data to this field.
In your case it would look like this. I show just a small working example, you can adjust it to your needs
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
#action(detail=True,
methods=['POST'])
def add_film_to_watch_list(self, request, **kwargs):
film = get_object_or_404(klass=Film, filmID=kwargs.get('filmID'))
user = self.get_object()
user.watchList.add(film)
return Response("Success")

How do I filter in URL a serializer when it's nested in another serializer In Django?

I'm creating an API that has nested data like in the picture
Now how to search nested data in URL here's my model
class Robot(models.Model):
robot = models.CharField(max_length=100)
short_Description = models.CharField(max_length=200)
status = models.CharField(max_length=20)
parameter = models.CharField(max_length=200)
jenkins_job = models.CharField(max_length=100, default='JenkinsJobName')
jenkins_token = models.CharField(max_length=100, default='JenkinsToken')
def __str__(self):
return self.robot
class assignParameter(models.Model):
parameterName = models.CharField(max_length=100, blank=True)
assignRobot= models.ForeignKey(Robot, on_delete=models.CASCADE, related_name='param', blank=True, null=True)
Here's my serializer.py
from .models import Robot,assignParameter
from rest_framework import serializers
class assignParameterSerializer(serializers.ModelSerializer):
class Meta:
model = assignParameter
fields = ['id', 'parameterName', 'assignRobot']
class RobotSerializer(serializers.ModelSerializer):
param = assignParameterSerializer(many=True, read_only=True)
JenkinJobName = jenkinsHistorySerializer(many=True, read_only=True)
class Meta:
model = Robot
fields = ['id', 'robot', 'short_Description', 'status', 'parameter', 'jenkins_job', 'jenkins_token', 'param']
and here's my view for the api
class RobotViewSet(viewsets.ModelViewSet):
queryset = Robot.objects.all()
serializer_class = RobotSerializer
filter_backends = [filters.DjangoFilterBackend]
filterset_fields = ['robot', 'JenkinJobName__jenkinsBuildNumber']
authentication_classes = [BasicAuthentication]
permission_classes = [IsAuthenticated]
in the API URL if I want to search a particular robot then using this URL URL/?robot=robotname I'm able to search that particular robot. But how can I search particular nested data using URL?
using my view I'm getting search filters like this
But that is not performing any Search. how to achieve that search and what is wrong with my code can someone please help me?
Actually when i search nested serializer only searched value should be present in list other should to be disappear.
Maybe you will need to overwrite your list method in your view, here it is how actually works, you can add whathever you want to filter or maybe you will need to overwrite your queryset depending on the parameters you want.

POST data only if you are authenticated and only to your user using django-rest-framework

i'm new to Django so sorry if this seems stupid.
i want to add an item to a database only if the user is authenticated .
here are the models:
class SaleItems(models.Model):
product_name = models.CharField(max_length=50)
price = models.IntegerField()
product_type = models.CharField(max_length=25)
description = models.CharField(max_length=250 ,default='', blank=True)
brand = models.CharField(max_length=25, null=True,blank=True)
image_path = models.ImageField(upload_to='images/product_image')
date_added = models.DateField(auto_now_add=True)
in_stock = models.BooleanField(default=True)
def __str__(self):
return f"{self.product_name}, price={self.price}"
class SaleHistory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(SaleItems, on_delete=models.RESTRICT, default=None)
date_bought = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.date_bought}, {self.product}, {self.user}'
the serializers:
class SaleItemSerializer(serializers.ModelSerializer):
class Meta:
model = SaleItems
fields = '__all__'
class SaleHistorySerializier(serializers.ModelSerializer):
class Meta:
model = SaleHistory
fields = '__all__'
urls:
routes = routers.DefaultRouter()
routes.register('api/saleitems', SaleItemViewSet, basename='saleitem')
routes.register('api/salehistory', SaleHistoryViewSet, basename='salehistory')
urlpatterns = [ path('',include(routes.urls))
]
and finally the apis
class SaleItemViewSet(viewsets.ModelViewSet):
queryset = SaleItems.objects.all()
permission_classes = [permissions.AllowAny]
serializer_class = SaleItemSerializer
class SaleHistoryViewSet(viewsets.ModelViewSet):
# queryset = SaleHistory.objects.all()
permission_classes = [permissions.IsAuthenticated]
serializer_class = SaleHistorySerializier
def get_queryset(self):
user = self.request.user
return SaleHistory.objects.filter(user = user)
so the problem, when i post to 'api/salehistory' i am able to add content to any user not only as the authenticated user.
(using knox authtoken for authentication).
Say for example i am authenticated as user1 and i have my auth token. Now I can use that token to add items to the SaleHistory model for any user which is very much undesired.
how can i solve this?
once again sorry for the crude description. first time asking question here.
First, set the user field as read_only by using read_only_fields meta option
class SaleHistorySerializier(serializers.ModelSerializer):
class Meta:
model = SaleHistory
fields = '__all__'
read_only_fields = ("user",)
Now, the SaleHistorySerializier will not accept the data from the user field.
Then, You need to override the perform_create(...) method of the SaleHistoryViewSet class
class SaleHistoryViewSet(viewsets.ModelViewSet):
# queryset = SaleHistory.objects.all()
permission_classes = [permissions.IsAuthenticated]
serializer_class = SaleHistorySerializier
def get_queryset(self):
return SaleHistory.objects.filter(user=self.request.user)
def perform_create(self, serializer):
serializer.save(user=self.request.user)

Django REST Framework - Query models by field value

I have a Building model for which I have created a Serializer and ModelViewSet. Now I am able to get all Buildings with /api/buildings/ and get a Building object with /api/buildings/3 where 3 is the Building Id.
How do I query for a Building object with a particular attribute value? For example, how do I get the Building object with name == "hospital"? Something like /api/buildings?name=hospital does not work.
views.py
class APIBuildingsViewSet(viewsets.ModelViewSet):
queryset = Building.objects.all()
serializer_class = BuildingSerializer
models.py
class Building(models.Model):
building_id = models.AutoField('ID', auto_created=True, primary_key=True)
name = models.CharField('Name', max_length=125, null=True, blank=False, unique=False)
address = models.CharField('Address', max_length=256, null=False, blank=False)
user_id = models.ForeignKey('accounts.User', on_delete=models.CASCADE, default=1)
def __str__(self):
return self.name
serializers.py
class BuildingSerializer(serializers.ModelSerializer):
class Meta:
model = Building
fields = ('building_id', 'name', 'address', 'user_id')
urls.py
router = DefaultRouter()
router.register(r'buildings', views.APIBuildingsViewSet, base_name='buildings')
urlpatterns = [
url(r'^api/', include(router.urls)),
]
You need to use DjangoFilterBackend in your view, and specify which fields can be used to filter.
First you must install it with pip install django-filter, and add django_filters to settings.py/INSTALLED_APPS, and set your view like this:
...
from django_filters.rest_framework import DjangoFilterBackend
class APIBuildingsViewSet(viewsets.ModelViewSet):
queryset = Building.objects.all()
serializer_class = BuildingSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = (building_id, name, address, user_id)
Whit these settings, you would be able to send a post like /api/buildings/?name=hospital (be aware of the slash before the question mark)
just change in your view.py file
views.py
from django_filters.rest_framework import DjangoFilterBackend
class APIBuildingsViewSet(viewsets.ModelViewSet):
queryset = Building.objects.all()
serializer_class = BuildingSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name', 'address']

Django Rest queryset filter by url parameter

I need to filter queryset in ListAPIView depending on url parameter. Basically, application lists all attendees (User) of an event with a call to API like /events/:id/attendees/
You can find serializers, models, urls and views below. I also wonder any other practices to do such end-point implementation in Django REST
**serializers.py**
class AttendeeSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Attendee
fields = ('user', 'status')
**views.py**
class EventAttendeeList(generics.ListAPIView):
queryset = Attendee.objects.all()
serializer_class = AttendeeSerializer
#permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self):
# It should filter attendees by event_id posted in URL
return Attendee.objects.all()
**urls.py**
url(r'^events/(?P<pk>[0-9]+)/attendees/$', views.EventAttendeeList.as_view()),
**models.py**
class Event(models.Model):
name = models.CharField(max_length=500, blank=True)
attendees = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Attendee', related_name='attendees_event')
class Attendee(models.Model):
event = models.ForeignKey(Event, related_name="a_event")
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="a_user")
requested_on = models.DateTimeField(default=timezone.now)
You can access the url parameter in your view with self.kwargs['parameter_name'] ( http://www.django-rest-framework.org/api-guide/filtering#filtering-against-the-url ). So the simplest solution would be
def get_queryset(self):
return Attendee.objects.filter(event=self.kwargs['pk'])