Send an email once object meets certain criteria - python

[Hopefully I entitled this post correctly]
I have a (sort of) 'follow' twitter thing going on. Users can follow a company profile object, which creates a follower object.
class Follower(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
profile = models.ForeignKey(UserProfile)
company = models.ForeignKey(Company)
verified = models.BooleanField(default=False)
from_user = models.BooleanField(default=False)
...
class Company(models.Model):
owner = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=200)
... and more fields that aren't relevant
What I'd like to do is send an update email to the company profile owner, after 5 new followers. 'You have 5 new followers!'.
As of right now I'm sending an email to the owner every time they get a new follower. A little much, I know.
I'm guessing I need to create a list of followers, send it, and then delete it to prepare for 5 new followers? I'm really not sure how to go about this. Any help or suggestions are greatly appreciated.
view:
#login_required
# this is creating a follower. Maybe I shouldn't send the email through this?
def follow(request, id):
company = Company.objects.get(id=id)
profile = get_object_or_404(UserProfile, user__username=request.user.username)
try:
follower = Follower.objects.get(profile=profile, company=company)
if not follower.verified:
follower.verified = True
follower.save()
messages.success(request, 'Now following %s\''%company.name)
mes = Message(subject="New Follower", sender=profile, recipient=company.owner)
mes.body = render_to_string('emails/email-message/new_follower.html', RequestContext(request, {
'sender': profile,
'receiver': company.owner,
}))
except ObjectDoesNotExist:
messages.error(request, 'Failed to follow.')

Send the email every time the number of followers for a specific company becomes a multiple of 5, like so:
if not (Follower.objects.filter(company=company).count() % 5):
#send the email

Related

Django: how to use .filter( ) method in django?

I am trying to display quiz only for users that are registered in a particular course, i.e if a user is registered in a Frontend Crash Course i want them to see only the quiz related to that course they are registered in, and not all the quiz from the db.
i have a model UserCourse where i am storing all the courses a user have enrolled in, when i try filtering by that models while user_course is get like this below
user_course = UserCourse.objects.get(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i get this error get() returned more than one UserCourse -- it returned 3! Now i have changed .get() to .filter() like this
user_course = UserCourse.objects.filter(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i then get this error The QuerySet value for an exact lookup must be limited to one result using slicing.
What is the right way to write this query.
models.py
class UserCourse(models.Model):
user = models.ForeignKey(User , null = False , on_delete=models.CASCADE)
course = models.ForeignKey(Course , null = False , on_delete=models.CASCADE, related_name="usercourse")
class Quiz(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="quizzes")
title = models.CharField(max_length=255)
course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True, related_name="quizzes")
date = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True)
user_course = models.ForeignKey(UserCourse, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.title
The Problem in the Second Line
user_course = UserCourse.objects.filter(user=request.user)
quizzes=Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
remember that when You are using filter you get QuerySet not one object
if you want to return the quizes those related to user_course_queryset you can use __in filter
print(user_course) # print it to understand more
quizzes=Quiz.objects.filter(course__usercourse__in=user_course)
this will Return every Quiz Related to the QuerySet objects

Django objects order_by give me duplicates users

I am trying to get all users (excepted request.user) and order them by datetime of last message they received.
Maybe I am doing it wrong.
#login_required
def get_users(request):
if request.method == 'POST':
users = list(User.objects.filter(~Q(username = request.user))
.order_by('personal_messages__sent_date').values())
return HttpResponse(dumps({'users': users}))
return redirect('message:index')
dumpsis from json_tricks.
Data are received by a Vue.js object with JS fetch
My models.py
from django.db import models
from django.conf import settings
class PersonalMessage(models.Model):
text = models.TextField()
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='personal_messages', null=True, on_delete=models.SET_NULL)
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
sent_date = models.DateTimeField('sent date', auto_now_add=True)
The thing is if I only do users = list(User.objects.filter(~Q(username = request.user)).values()) it works well but if I add the order_by users = list(User.objects.filter(~Q(username = request.user)) .order_by('personal_messages__sent_date').values()) I get duplicates for each user. Seems it returns each user n times if user is linked with n messages.
Maybe there is another way.
Any Idea?
You need to use aggregation and the query looks like this:
User.objects.filter(
~Q(username = request.user)
).annotate(
last_message_sent_date=Max('personal_messages__sent_date')
).order_by(
'last_message_sent_date'
)

show a list of rent contacted by specific buyer

I am a beginner of django-rest-framework. I am trying hard to understand the serializer and good api design. I dont want to dive directly into viewset and generics view like ListView, RetrieveAPIView and etc. I want to understand the serializer and APIView clearly so i drew the following criteria to solve them. However i could only solve 2 of the problem from below.
Here is the list of problems i drew to hone my rest api skill
"""
return a list of rent
"""
"""
return a list of rent or specific rent if token is give n
"""
"""
return a list of rent contacted by specific buyer
"""
"""
return a list of buyer that has contacted a specific rent
"""
Here is my model of Rent, Galleries and Contact. Rental and contact are separate app. Contact is to contact a rent owner to buy or rent the space listed by that owner.
class Rental(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=300, blank=False, null=False)
phone_number = models.PositiveIntegerField(null=False, blank=False)
rate = models.FloatField()
class Gallery(models.Model):
rent = models.ForeignKey(Rental, related_name="galleries")
image = models.FileField(upload_to=user_directory_path, null=True, blank=True)
tag = models.CharField(max_length=1, choices=TAGS, null=True, blank=True)
BUYER_CHOICES = (
('B', 'Buy'),
('R', 'Rent'),
)
class Contact(models.Model):
buyer = models.ForeignKey(User)
rental = models.ForeignKey(Rental, related_name="rent")
email_id = models.EmailField(blank=False, null=False)
buyer_choice = models.CharField(choices=BUYER_CHOICES, max_length=1, null=False, blank=False)
class GallerySerializer(serializers.ModelSerializer):
class Meta:
model = Gallery
fields = ('image', 'tag',)
class RentalSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
galleries = GallerySerializer(many=True)
class Meta:
model = Rental
fields = ('__all__')
UPDATED RentAPIView CODE AS PER #Remi
class RentAPIView(APIView):
serializer_class = RentalSerializer
parser_classes = (FormParser, MultiPartParser,)
def get(self, request, token=None, format=None):
"""
Returns a list of rents (or just rent if token is given)
"""
reply = {}
try:
rents = Rental.objects.filter(user=request.user)
# code is updated here
buyer_id = self.request.query_params.get('buyer_id', None)
if buyer_id:
rents = rents.filter(user__contact_set__buyer_id=buyer_id)
if token:
rent = rents.get(id=token)
reply['data'] = RentalSerializer(rent).data
else:
reply['data'] = RentalSerializer(rents, many=True).data
except Rental.DoesNotExist:
return error.RequestedResourceNotFound().as_response()
except:
return error.UnknownError().as_response()
else:
return Response(reply, status.HTTP_200_OK)
Sorry for posting long code. I just wanted to show i tried my best to design effective rest api but could not solve the last 2 problem.
Can anyone kindly help me to understand on how to handle the following criteria?
I would strongly suggest using the viewsets. In your case, the ModelViewSet would do, if you override your get_queryset function in order to prefilter your queryset by anything you want. For Example:
class RentAPIViewset(viewsets.ModelViewSet):
serializer_class = RentalSerializer
def get_queryset(self):
# if requesting something like /api/rent?buyer_id=1
buyer_id = self.request.query_params.get('buyer_id', None)
if buyer_id:
return Rental.objects.filter(rent__buyer__id=buyer_id)
return Rental.objects.all()
This would be much cleaner uses the core-functionality of DRF. That being said, back to your question, you could use some of the logic above to extend your api view:
with query params (you could also go with the kwargs approach like you did with the token):
class RentAPIView(APIView):
serializer_class = RentalSerializer
parser_classes = (FormParser, MultiPartParser,)
def get(self, request, token=None, format=None):
"""
Returns a list of rents (or just rent if token is given)
"""
reply = {}
try:
# first of your two remaining problems
# if requesting something like /api/rent?buyer_id=1
buyer_id = self.request.query_params.get('buyer_id', None)
rents = Rental.objects.filter(user=request.user)
if buyer_id:
rents = rents.filter(rent__buyer__id=buyer_id)
if token:
rent = rents.get(id=token)
reply['data'] = RentalSerializer(rent).data
else:
reply['data'] = RentalSerializer(rents, many=True).data
except Rental.DoesNotExist:
return error.RequestedResourceNotFound().as_response()
except:
return error.UnknownError().as_response()
else:
return Response(reply, status.HTTP_200_OK)
The last of your problems doesn't return Rent-Objects, but rather User objects, so this should be done in a differen API view.

How to authenticate if a user "owns" a model instance

I have the following models:
class UserProfile(models.Model):
user = models.OneToOneField(User)
class Site(models.Model):
user = models.ForeignKey(User)
site_name = models.CharField(max_length=128, blank=False, null=False)
class Team(models.Model):
site = models.ForeignKey(Site)
team_member_name = models.CharField(default='name', max_length=128, blank=False, null=False)
I have a view that passes a team_member id via the URL:
Urls.py:
url(r'^team/(?P<team_member_id>\d+)/$', 'team.views.home', name='team_view_team_member')
Views.py:
#login_required
def home(request, team_member_id=None):
team_member = Team.objects.get(id=team_member_id)
Note that there are many Team instances (i.e. lots of team members) which have the same Site_id.
How can I test if the request.user has the same site_id as any team_member returned? Is there a simple way to repeat this if I want to use it across multiple views?
Try this:
team_member = Team.objects.get(id=team_member_id)
if team_member.site.id == request.user.site_set.all().first().id:
print "same site"
else:
print "different site"
Hope this helps.
# Site for user in request
req_user_site = Site.objects.get(user=request.user) # Use filter if it will return more than one object
# Site for team member in url
sites = Site.objects.filter(team__pk=team_member_id)
# Then compare
if req_user_site in sites:
print "have the same"
else:
print "don't"

django doesn't save manytomany object

I have this models
class Base(models.Model):
city = models.CharField(max_length=100)
district = models.CharField(max_length=100)
Owner = models.ForeignKey(User, related_name='%(class)s__Game_Owner')
attending = models.ManyToManyField(User)
requested = models.ManyToManyField(User, related_name="%(class)s__requested")
invited = models.ManyToManyField(User, related_name="%(class)s__invited")
teams = models.ManyToManyField(Team)
field = models.CharField(max_length=100)
Hash = models.CharField(max_length=32, blank=True)
and I have other two classes inherting from this base. The class names are
reservation and enlisting
I created this function in the views
def test_join_event(event_id, event_type, user_id):
event = None
if event_type =='enlisting':
event = enlistings.objects.get(id=event_id)
elif event_type =='reservation':
event = reservations.objects.get(id=event_id)
requested_user = User.objects.get(id=user_id)
if requested_user == event.Owner:
return "Error: you are already part of the event"
if requested_user in event.players.all():
return "Error 2!"
if requested_user in event.invited.all():
return "You are already invited to the event!"
if requested_user in event.requested.all():
return "You can't send your request again!"
event.requested.add(requested_user)
event.save()
return "Saved!!"
when I call the function from the interpreter it keeps giving me "Saved" however it should add the user to the requested list and the next time I call the function it returns "You can't send your request again" !!!
I tried the function from the browser it returns saved too, but when I look at the object in the interpreter I see that the requsted list is empty (doesn't have the player I just added)
When I checekd from the interpreter I got the same problem!! I only noticed that I only can add the user who owns that event.
for example like this code
event.requested.add(event.owner)
event.requested.all() # The user is added successfully !!
I can't understand why this is happening. Any ideas??

Categories