Filtering users based on date joined - django-rest-framework

I am trying to filter users based on the date joined. but it somehow it requires the time also even though i formatted it to only have the date, for example "2020-05-08".
class UserSerializer(serializers.ModelSerializer):
date_joined = serializers.DateTimeField(
format='%Y-%m-%d', input_formats=None)
class Meta:
model = User
fields = ['__all__']
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [ DjangoFilterBackend]
filterset_fields = ['date_joined']
{
"date_joined": [
"Enter a valid date/time."
]
}

You should use DateField in your serializer instead of DateTimeField:
https://www.django-rest-framework.org/api-guide/fields/#datefield
If you have the DateTimeField in your model (and I guess, you are, as it seems, that you are using standard User) you will need to use the corresponding serializer field. If you want to have the DateTimeField in your model, but filter only by the date you should customize your view/serializer/filter.
The easiest way to do it will be something like:
class UserViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = UserSerializer
def get_queryset(self):
some_date = self.request.GET.get('date')
qs = User.objects.all()
if date:
#filter depends of what exactly do you want
return qs.filter(date_joined__contains=some_date)
return qs
You can check out the examples of date filters here:
How do I filter query objects by date range in Django?

Related

Django REST: Exclude some fields and filter a nested serializer

I am trying to exclude the field "prospect" from the Appointment serializer, which is nested under the Unit Serializer.
As you can see below, due to some data manipulation on the Appointment queryset, I decided to use a SerializerMethodField to define the Appointment serializer. However, I am not sure how to exclude fields when using a SerializerMethodField.
Alternatively, I could use a ModelSerializer for the Appointment, which allows me to define which fields to include, but then I would not be able to manipulate the data the way I want.
Note sure what to do.
Models
class Appointment(models.Model):
appointment_time = models.DateTimeField()
unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
staff = models.ForeignKey(Staff, on_delete=models.CASCADE)
prospect = models.ForeignKey(Prospect, on_delete=models.CASCADE)
Serializers
class UnitSerializer(serializers.ModelSerializer):
availability = SerializerMethodField()
manager = ManagerSerializer()
instruction = InstructionSerializer(source='instruction_set', many=True)
appointment = SerializerMethodField()
class Meta:
model = Unit
fields = ['id', 'address', 'manager', 'availability', 'instruction', 'appointment']
def get_availability(self, instance):
queryset = instance.availability_set.order_by('start_time')
return AvailabilitySerializer(queryset, many=True).data
def get_appointment(self, instance):
start_buffer = 0.5 ## How many hours from now do we start displaying appointments in the queue
end_buffer = 72 ## How many hours from now do we stop displaying appointments in the queue
start_cutoff = datetime.now() + timedelta(hours=start_buffer)
end_cutoff = datetime.now() + timedelta(hours=end_buffer)
queryset = instance.appointment_set.exclude(appointment_time__lt=start_cutoff).exclude(appointment_time__gt=end_cutoff).order_by('appointment_time')
return AppointmentSerializer(queryset, many=True).data
JSON Object Representation

How to restrict fields when creating post request in DRF?

I am making a POST api using DRF. In that api, I need only few fields(name, size, customer_name, customer_address), but don't require this fields(status, ordered_time) because these fields I want to save these fields in run time as status='open' and ordered_time=DateTimeField.now()
views.py
class PizzaOrderCustomerView(APIView):
def post(self, request):
orders = request.data.get('orders')
# Create an article from the above data
serializer = ArticleSerializer(data=orders)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '{}' created successfully".format(article_saved.name)})
models.py
class PizzaOrder(models.Model):
name = models.CharField(max_length=120)
size = models.CharField(max_length=10, choices=SIZE_CHOICE, default='MEDIUM')
customer_name = models.CharField(max_length=120)
customer_address = models.TextField()
ordered_time = models.DateTimeField(default=timezone.now, editable=False)
status = models.CharField(max_length=20, default='open', editable=False)
serializers.py
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
# fields = '__all__'
read_only_fields = ('status',)
But when I try to create an order, it needed status and ordered_time also. But it should save at the time of creating order automatically.
Suggest a good way to do it.
from rest_framework import viewsets, mixins
class PizzaViewsets(viewsets.ViewSet, mixins.CreateModelMixin):
model = PizzaOrder
serializer_class = OrderSerializer
queryset = model.objects.all(
serializer, it is always good practise to mention all fields instead of
all
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = ('status','ordered_time','name', 'size', 'customer_name', 'customer_address',)
read_only_fields = ('status','ordered_time',)

Multiple endpoints for a single model in REST framework

I have a REST framework app for a multi-page form:
class InformationRequest(models.Model):
# user information
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
# contact details
phone = models.CharField(max_length=60)
email = models.CharField(max_length=60)
I'm trying to create endpoints for each of the two blocks of data within the model:
UserInformationSerializer(serializers.Serializer):
first_name = serializers.CharField(max_length=60)
last_name = serializers.CharField(max_length=60)
ContactDetailsSerializer(serializers.Serializer):
phone = serializers.CharField(max_length=60)
email = serializers.CharField(max_length=60)
I'd like the endpoints to look like:
requests/1/user-informtion
requests/1/contact-details
But I'm unsure of how to structure the view to achieve this. Currently I'm using a model viewset:
class InformationRequestViewSet(viewsets.ModelViewSet):
queryset = InformationRequest.objects.all()
serializer_class = ??
Is it possible to have two serializers for one model?
It's certainly possible to have 2 (or any number of) serializers for a model. And you are on the right path. What you want is different urls mapping to different views. So in your case, it can be something like the following:
Note that I turned each of your serializers into a ModelSerializer.
path-to/serializers.py
class UserInformationSerializer(serializers.ModelSerializer):
class Meta:
model = InformationRequest
fields = ('first_name', 'last_name')
class ContactDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = InformationRequest
fields = ('phone', 'email')
Next, we have 2 different urls that point to 2 different views:
path-to/urls.py
urlpatterns = [
url(r'^requests/(?P<pk>\d+)/user-information/$', views.UserInformationDetail.as_view()),
url(r'^requests/(?P<pk>\d+)/contact-details/$', views.ContactInformationDetail.as_view()),
# ... other urls
]
And finally, the views themselves (I'm using generic RetrieveAPIView for convenience)
path-to/views.py
class UserInformationDetail(generics.RetrieveAPIView):
queryset = InformationRequest.objects.all()
serializer_class = UserInformationSerializer
class ContactInformationDetail(generics.RetrieveAPIView):
queryset = InformationRequest.objects.all()
serializer_class = ContactDetailsSerializer

How do I specify multiple column name in a Django search field?

i use django filter backend
I define multiple columns in a search field, as follows:
class tableViewSet(ModelViewSet):
"""
A simple ViewSet for viewing and editing accounts.
"""
queryset = table.objects.all()
serializer_class = WebSerializer
pagination_class = StandardResultsSetPagination
filter_backends = (DjangoFilterBackend,SearchFilter)
search_fields = ('name','family','tel',)
i want to make an api that handle some query like this:
select * from table1 where name like ('tom') and family like ('%anderson%') and tel like ('%0223654%')
Is there any way to specify the column name in the API?
For example:
http://127.0.0.1/api-user/table/search?name=tom&family=andeson&tel=0223455
You should rather use DjangoFilterBackend instead of SearchFilter if you want to filter per specific attribute.
As you are not looking for exact search, you will have to create a FilterSet and use filter_class in you view.
Something like:
class TableFilter(django_filters.FilterSet):
name = django_filters.CharFilter(name='name', lookup_expr='icontains')
family = django_filters.CharFilter(name='family', lookup_expr='icontains')
tel = django_filters.CharFilter(name='tel', lookup_expr='icontains')
class Meta:
model = table
fields = ['name', 'family', 'tel']
class tableViewSet(ModelViewSet):
"""
A simple ViewSet for viewing and editing accounts.
"""
queryset = table.objects.all()
serializer_class = WebSerializer
pagination_class = StandardResultsSetPagination
filter_backends = (DjangoFilterBackend,SearchFilter)
filter_class = TableFilter
Specifying the field in the query string is unnecessary. The following request should work:
http://127.0.0.1/api-user/table?search=something
relevant docs

Passing argument from view to Custom RelatedField serializer

How can I pass an argument to a serializers.RelatedField class from views.py. I need to pass language_id to query Language.objects model within that RelatedField.
I am not sure if I took a right approach to this issue. What I want to achieve is to present information about genres associated to a movie from database model about depending on the language. The MovieGenre model has genre ID field which I want to replace with actual Genre name.
My serialiser.py
class GenreField(serializers.RelatedField):
def to_representation(self, value, language_id=1):
genre_name = GenresVideo.objects.get(genre_id=value, language_id=language_id)
return genre_name.name
class MovieGenresSerializer(serializers.ModelSerializer):
genre_id = GenreField(read_only=True)
class Meta:
model = MoviesGenres
As you see, here I query Language.objects with default value but I would like to pass it from views (language_id).
My views.py:
class MovieGenresTestViewSet(viewsets.ModelViewSet):
lookup_field = 'movie'
queryset = MoviesGenres.objects.all()
serializer_class = MovieGenresSerializer
def list(self, request, language_pk):
queryset = MoviesGenres.objects.all()
serializer = MovieGenresSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, movie, language_pk):
queryset = MoviesGenres.objects.filter(movie=movie)
serializer = MovieGenresSerializer(queryset, many=True)
return Response(serializer.data)
And my urls.py:
router.register(r'lang', LanguagesViewSet, base_name='lang')
mov_gen = routers.NestedSimpleRouter(router, r'lang', lookup='language')
mov_gen.register(r'mg', MovieGenresTestViewSet, base_name='mg')
url(r'^api/', include(genre_spec.urls))
My models.py
class Languages(models.Model):
name = models.CharField(unique=True, max_length=255)
short_name = models.CharField(unique=True, max_length=4, blank=True, null=True)
active = models.BooleanField(default="")
class Meta:
managed = False
db_table = 'languages'
ordering = ('id',)
class GenresVideo(models.Model):
genre_id = models.IntegerField()
language = models.ForeignKey('Languages')
name = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'genres_video'
unique_together = (('genre_id', 'language'),)
ordering = ('genre_id',)
class MoviesGenres(models.Model):
movie = models.ForeignKey(Movies)
genre_id = models.IntegerField()
class Meta:
managed = False
db_table = 'movies_genres'
unique_together = (('movie', 'genre_id'),)
Through the urls routes, I can get a correct response from API including the language_id. I just need to pass it to the view somehow.
Thanks a lot for help!
I'll try to answer to your first question, with the easiest implementation possible: SerializerMethodField. Because we will get the language id via the context passed to the serializer, we should either generate the context for the serializer, or let the framework do that for us.
Now to the problem at hand: you aren't filtering the queryset (MoviesGenres) by language per se. Thus, we can avoid overwriting the list and retrieve methods. Nevertheless, the router mechanism will inject in kwargs for the view method the language_pk parameter - that's the parameter that we will retrieve from within the serializer context:
class MovieGenresSerializer(serializers.ModelSerializer):
genre = searializers.SerializerMethodField()
class Meta:
model = MoviesGenres
def get_genre(self, instance):
# get the language id from the view kwargs
language_id = self.context['view'].kwargs['language_pk']
# get the genre
try:
genre_name = GenresVideo.objects.get(genre_id=instance.genre_id, language_id=language_id).name
except GenresVideo.DoesNotExist:
genre_name = None
# return the formatted output
return genre_name
class MovieGenresTestViewSet(viewsets.ModelViewSet):
lookup_field = 'movie'
queryset = MoviesGenres.objects.all()
serializer_class = MovieGenresSerializer

Resources