Add payment in django project to extend an expiration date of posts./ - django

I have a project where the user can post an Ad and this Ad will be available only for 30 days.
I need to add a payment method to extend the Expiration date of the Ad.
Here is my Ad creation view .
class AdvertiseCreateView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
serializer = AdvertiseSerializer(data=request.data)
user = request.user
if serializer.is_valid():
print(user)
serializer.save(owner = user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
List view:
class AdvertisesListView(APIView):
def get(self, request):
advertises = Advertise.objects.filter(Q (expiration_date__gt = Now()))
serializer = AdvertiseSerializer(advertises, many=True)
return Response(serializer.data, status = status.HTTP_200_OK)
Models:
class Advertise(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="advertise")
category = models.CharField(max_length= 200, choices = CATEGORY)
location = models.CharField(max_length= 200, choices = LOCATIONS)
description = models.TextField(max_length=600)
price = models.FloatField(max_length=100)
expiration_date = models.DateField(default = Expire_date, blank=True, null=True) #Expire date come from another file
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
class Meta:
ordering = ['created_at']
def __str__(self):
return self.category
So the thing is when the user make his payment the expire date extends.
I need help in payment part.
Thanks in Advance.

Related

How to filter in Django Rest Framework function based view?

So many documentation for filtering in Django rest framework but all the examples are in class based view. but I am trying to do the same in DRF function based view. I wanted to do multiple filter for my items queryset.
I tried one way and it is working perfectly. Here first I am trying to search by item name or restaurant name in one request. then I take another keyword and try to filter restaurant name or item name based on restaurant city. It is working perfectly like if I hit this url
http://localhost:8000/api/items/?keyword=lasagne&keyword1=paris
then it gives me the perfect response.
But What I am asking for is that now my code looks for this specific part is messy and I want to add more fields for multiple filtering. Which procedure to follow? Should I follow this one and multiple requests and trying to filter from this.
Suppose now I want to filter the queryset based on dish_type, price, item_type, location and then search for items by name or restaurants by name
#this is my models
class Restaurant(models.Model):
user = models.OneToOneField(CustomUser, related_name='restaurant', on_delete=models.CASCADE, null=False)
name = models.CharField(max_length=200, blank=True, null=True)
profile_picture = models.ImageField(null=True, blank=True)
address = models.TextField(max_length=2000, blank=True, null=True)
city = models.CharField(max_length=200)
latitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
longitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
is_verified = models.BooleanField(default=False)
createdAt = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.name)
class Item(models.Model):
user = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
name = models.CharField(max_length=220)
image = models.ImageField(null=True, blank=True)
dish_type = models.ForeignKey(Dishtype, on_delete=models.CASCADE)
item_type = models.ForeignKey(Itemtype, on_delete=models.CASCADE)
description = models.TextField(max_length=10000)
rating = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
numReviews = models.IntegerField(null=True, blank=True, default=0)
old_price = models.DecimalField(max_digits=11, decimal_places=2)
discount = models.IntegerField(blank=True, null=True)
price = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
countInStock = models.IntegerField(blank=True, null=True, default=0)
createdAt = models.DateTimeField(auto_now_add=True)
_id = models.AutoField(primary_key=True, editable=False)
def save(self, *args, **kwargs):
self.price = Decimal(self.old_price * (100 - self.discount) / 100)
return super(Item, self).save(*args, **kwargs)
class Meta:
ordering = ['-createdAt']
def __str__(self):
return self.name
#serializer
class RestaurantSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Restaurant
fields = '__all__'
def get_user(self, obj):
user = obj.user
serializer = UserSerializer(user, many=False)
return serializer.data
class ItemSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField(read_only=True)
dish_type = serializers.SerializerMethodField(read_only=True)
item_type = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Item
fields = '__all__'
def get_user(self, obj):
user = obj.user
serializer = RestaurantSerializer(user, many=False)
return serializer.data
def get_dish_type(self, obj):
dish_type = obj.dish_type
serializer = DishtypeSerializer(dish_type, many=False)
return serializer.data
def get_item_type(self, obj):
item_type = obj.item_type
serializer = ItemtypeSerializer(item_type, many=False)
return serializer.data
#views.py
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getItems(request):
user = request.user
query = request.query_params.get('keyword')
if query == None:
query = ''
cuery = request.query_params.get('keyword1')
if cuery == None:
cuery = ''
items = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all().filter(
Q(name__icontains = query) | Q(user__name__icontains = query))
else:
restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all(
).filter(Q(user__city__iexact = cuery))
items = restaurant_city.filter(Q(name__icontains = query) | Q(user__name__icontains = query))
serializer = ItemSerializer(items, many=True)
return Response(serializer.data)
######Updated solved the problem
#filters.py
class ItemFilter(django_filters.FilterSet):
numReviews = django_filters.NumberFilter()
numReviews__gt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='gt')
numReviews__lt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='lt')
name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Item
fields = ['_id', 'dish_type__id']
#views
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getItems(request):
user = request.user
queryset = Item.objects.all()
filterset = ItemFilter(request.GET, queryset=queryset)
if filterset.is_valid():
queryset = filterset.qs
serializer = ItemSerializer(queryset, many=True)
return Response(serializer.data)
now data are passing like this
http://localhost:8000/api/items/?numReviews__gt=20&numReviews__lt=22
You can use queryset and override get_queryset function.
class FooViewSet(GenericViewSet, mixins.ListModelMixin):
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated]
serializer_class = ItemSerializer
def get_queryset(self):
query = self.request.query_params.get('keyword', '')
if not self.request.query_params.get('keyword1'):
items = Item.objects.select_related('user').select_related('dish_type').select_related(
'item_type').all().filter(
Q(name__icontains=query) | Q(user__name__icontains=query))
else:
restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related(
'item_type').all(
).filter(Q(user__city__iexact=self.request.query_params.get('keyword1', '')))
items = restaurant_city.filter(Q(name__icontains=query) | Q(user__name__icontains=query))
return items

Custom decorator on class based views in django rest framework

I have the following models in my application
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
employee_name = models.CharField(max_length=500, default=0)
employee_email = models.EmailField(max_length=500, default=0)
employee_phone = models.CharField(max_length=500, default=0)
employee_city = models.CharField(max_length=500, default=0)
employee_role = models.CharField(max_length=100, default='View')
class GroupModels(models.Model):
model_coices = (('Product', 'Product'), ('Kit', 'Kit'), ('Vendor', 'Vendor'), ('Warehouse', 'Warehouse')
, ('Flow', 'Flow'), ('ReceiverClient', 'ReceiverClient'))
models = models.CharField(max_length=500, default=0, choices=model_coices)
class Group(models.Model):
name = models.CharField(max_length=500, default=0)
emp = models.ForeignKey(Employee, on_delete=models.CASCADE)
models = models.ManyToManyField(GroupModels)
This is an attempt to create custom permissions for every Employee to do something
Now I have the following View to create Product
class ProductCreateAPIView(CreateAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = ProductSerializer
def post(self, request, *args, **kwargs):
owner = request.user.pk
d = request.data.copy()
d['owner'] = owner
serializer = ProductSerializer(data=d)
if serializer.is_valid():
serializer.save()
print("Serializer data", serializer.data)
o = Product.objects.get(id=serializer.data['id'])
ow = User.objects.get(id=owner)
Inventory.objects.create(product=o, quantity=0, owner=ow)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
How do I create a decorator to give access of this function to only those employees who have Product in the Group model?

how to get Json response formatted differently on django

I have a custom user model and i implemented a user following and follower system that works well. But the problem I have is that when I request for the followers a particular user has, the JSON response I get is not exactly the way I want it returned. more details below
models
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=250)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=255, unique=True, blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
class FollowLog(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='followers')
followed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,
related_name='following', null=True)
followed_on = models.DateTimeField(auto_now_add=True)
status = models.CharField(choices=FOLLOW_STATUS, default=FollowStatus.following.value, max_length=30)
updated_on = models.DateTimeField(auto_now=True)
unfollowed_on = models.DateTimeField(null=True)
blocked_on = models.DateTimeField(null=True)
serializer
class FollowerSerializer(serializers.ModelSerializer):
'''
Allows people to view follower of a user
'''
followed_by = serializers.SlugRelatedField(read_only=True, slug_field='slug')
class Meta:
model = FollowLog
fields = ('followed_by',)
read_only_fields = ('followed_by',)
view
class UserFollowerView(APIView):
'''
Gets all the followers to a user
'''
permission_classes = [AllowAny]
def get(self, request, slug):
user = User.objects.get(slug=slug)
followers = user.followers.all().filter(status='following').order_by("-followed_on")
serializer = FollowerSerializer(followers, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
when I run the above, I get the appropriate response but in this format
JSON response I get
[
{
"followed_by": "opeyemi-odedeyi-qqmunu13o4b8vd4"
},
{
"followed_by": "modupeoluwa-odedeyi-m7ji5qj5szu2uqo"
}
]
I would prefer it if I got a response like below
preferred response I want to get
{
"followed_by": [
"opeyemi-odedeyi-qqmunu13o4b8vd4",
"modupeoluwa-odedeyi-m7ji5qj5szu2uqo"
]
}
A serializer will always return a dictionary, and if you set many=true, it will return an array of dictionaries.
What you can do is to get the array you want from the array of dictionaries returned by the serializer:
class UserFollowerView(APIView):
'''
Gets all the followers to a user
'''
permission_classes = [AllowAny]
def get(self, request, slug):
user = User.objects.get(slug=slug)
followers = user.followers.all().filter(status='following').order_by("-followed_on")
data = FollowerSerializer(followers, many=True).data
data_to_return = list(map(lambda item: item['followed_by'], data))
return Response(data_to_return, status=status.HTTP_200_OK)
You can make a custom renderer for your api and change the format of the response however so you want.
class UserFollowerView(APIView):
'''
Gets all the followers to a user
'''
permission_classes = [AllowAny]
renderer_classes = (UserFollowerRenderer, )
def get(self, request, slug):
user = User.objects.get(slug=slug)
followers = user.followers.all().filter(status='following').order_by("-followed_on")
serializer = FollowerSerializer(followers, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
and the renderer can be something like this :-
class UserFollowerRenderer(CoreJSONRenderer):
charset = "utf-8"
def render(self, data, media_type=None, renderer_context=None):
if not data:
return "[]"
final_data = list()
for element in data:
final_data.append(element.get('followed_by'))
result = dict(followed_by=final_data)
return json_dumps(result)

How to make relation with all_auth/rest_auth user to some model. with cookie/token

I am using all_auth and rest_auth along with Angular. I have a model called Campaign
class Campaign(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100)
hashtag = models.CharField(max_length=20)
message = models.CharField(null=True, blank=True, max_length=100)
sale_limit = models.IntegerField(null=True, blank=True)
start_date = models.DateField(null=True, blank=True)
expiry_date = models.DateField(default=now_plus_30)
product_url = models.CharField(max_length=100)
created_at = models.DateTimeField(default=datetime.now, blank=True)
modified_at = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(User, unique=False)
def __str__(self): # __unicode__ on Python 2
return self.name
and a view as
class ListCreateCampaign(APIView):
"""
List all Campaigns or create one.
"""
def post(self, request, format=None):
serializer = CampaignSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I don't want to pass user_id from via API, how do I get the user details and inject it in request.data
One approach could be, make user field optional in serializer by making required=False. Then pass the user while calling .save() method of serializer like .save(user=request.user). For more info http://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save

Django Rest Framework PUT request on unique model field

I have the following model
class Owner(models.Model):
user = models.OneToOneField(User, default=1, editable=True)
phone = models.CharField(max_length=40, null=True, blank=True)
address = models.CharField(max_length=255, null=True, blank=True)
city = models.CharField(max_length=255, null=True, blank=True)
state = USStateField(null=True, blank=True)
zip = models.CharField(max_length=20, null=True, blank=True)
def __str__(self):
return "%s %s" % (self.user.first_name, self.user.last_name)
class Device(CreationModificationMixin):
_STATUSES = (
('A', 'Active'),
('I', 'Inactive'),
('F', 'Failure'),
)
_TYPES = (
('S', 'Spa'),
('P', 'Pool'),
)
udid = models.CharField(max_length=255, verbose_name="Unique ID / MAC Address", null=False, blank=False, unique=True)
type = models.CharField(max_length=1, choices=_TYPES, null=False, blank=False)
title = models.CharField(max_length=255, null=False, blank=False)
status = models.CharField(max_length=1, default='A', choices=_STATUSES)
pinged = models.DateTimeField(null=True)
owner = models.ForeignKey(Owner, verbose_name="Owner", null=True, blank=True)
def __str__(self):
return self.udid
I have the following serializer
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Device
fields = ('id', 'udid', 'title', 'type', 'status', 'pinged', 'created')
I have the following API View defined:
class DeviceAPIView(APIView):
permission_classes = (IsAuthenticated,) # explicit
code_404 = "Device doesn't exists"
def get(self, request, device_id):
try:
d = Device.objects.get(id=device_id, owner=request.user.owner)
except Device.DoesNotExist:
return Response({'error': self.code_404}, 404)
serializer = DeviceSerializer(d)
return Response(serializer.data)
def put(self, request, device_id):
serializer = DeviceSerializer(data=request.DATA)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
data = serializer.data
data['id'] = id
d = Device(**data).save()
serializer = DeviceSerializer(d)
return Response(serializer.data, status=status.HTTP_200_OK)
PUT request on existing device
{
"udid": "38-2C-4A-47-C2-ED",
"title": "Backyard pool",
"type": "S"
}
gives me back
{
"udid": ["This field must be unique."]
}
However I'm updating the record and passing the same UDID it has. So I'm not getting a duplicate in DB but DRF thinks the other way.
What I need to achieve is
If UDID of the same record is not changed - then no error should be raised
if UDID of the record changes and now it's the same as some of record's UDID then error should be returned.
As per the comments implementing the put method closer to the reference implementation in the docs should fix the issue.
def put(self, request, pk, format=None):
device = self.get_object(pk)
serializer = DeviceSerializer(device, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Saving instances has a bit more information on creating, updating and saving instances by using the serializer class methods.