Django ORM order_by - django-models

I have two models , Task and TaskComment :
class Task(models.Model):
title = models.CharField(max_length = 200)
creationDate = models.DateTimeField('date created')
lastUpdateDate = models.DateTimeField('date updated')
description = models.CharField(max_length = 5000)
class TaskComment(models.Model):
task = models.ForeignKey(Task, related_name='comments')
message = models.CharField(max_length = 5000)
creationDate = models.DateTimeField('date created')
Imagine a page where all tasks are listed. And thing i want to do is to order tasks by the number of comments linked to this task. I've tried several this like :
Task.objects.all().order_by("comments__count")
But it doesn't worked.
Can you help me ?

You need Annotation
from django.db.models import Count
Task.objects.all().annotate(num_comments=Count('taskcomment')).order_by('-num_comments')

Related

How can I create multiple related objects inside a view with cleaned data from two Django forms on the same page

I have 4 related Django Models ModifiedUser and Profile defined as follows . I am trying to create the person responsible for the activity,through a person model form. Through a person profile model form I am trying to add their profile details which includes the related person,country etc. Using these details I want to create a second person, called related user. Then I want to assign the two people to the activities via their Roles.
Models
'''
Class ModifiedUser:
email = models.EmailField(
max_length=255,blank=True,null=True,unique=True)
...
Class Profile:
modified_user = models.ForeignKey(ModifiedUser)
related_user = models.EmailField(
max_length=255,blank=True,null=True)
...
class Activity:
person = models.ManyToManyField(Profile,related_query_name='actor',related_name=' person', through='RoleAssignment')
class RoleAssignment:
person = models.ForeignKey(Profiles,on_delete=CASCADE,related_name="role")
feedback = models.ForeignKey(Activity,on_delete=CASCADE)
...
'''
Forms:
'''
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
class ModifiedUserForm(forms.ModelForm):
class Meta:
model = ModifiedUser
fields = '__all__'
'''
View
'''
from profiles.models import Profile, ModifiedUser,Activity
from .forms import ResponsibleForm, ModifiedUser
def add_activity_owner(request):
activity = Activity.objects.create(initiatedby=currentuser,updatedby=currentuser)
if request.method == 'POST':
responsibleform = ResponsibleForm(request.POST, request.FILES)
profileform = ProfileForm(request.POST, request.FILES)
if all([receiverform.is_valid(), detailform.is_valid()]):
owner_firstname =responsibleform .cleaned_data['Phone']
owner_lastname = responsibleform .cleaned_data['Address']
owner_email = responsibleform .cleaned_data['email']
relatedperson_email= profileform.cleaned_data['related_user'],
country = profileform.cleaned_data['country'],
gender = profileform.cleaned_data['gender'],
relatedperson,person_created = ModifiedUser.objects.get_or_create(email=relatedperson_email,FirstName=NULL,LastName=NULL)
owner,owner_created=Profiles.objects.get_or_create(email=owner_email,FirstName=owner_firstname,Lastame=owner_lastname)
owner_profile ,owner_created= Profiles.objects.get_or_create(user=owner,
related_user= relatedperson_email,
country = country,
gender = gender,
owner_role = RoleAssignment.objects.create(activity=activity,person=owner,role=role['owner'])
related_person_role = RoleAssignment.objects.create(activity=activity,person=relatedperson,role=role['actor'])
context['relateduser']=relateduser
context['owner']=owner
context['owner_role']=owner_role
return redirect(selectroles,activity)
else:
responsibleform = GiverForm()
profileform = UserProfileUpdateForm()
profileform':profileform})
return render(request,'addowner.html',context)
'''

Update a particular field in django forms and not be able to edit the others

I am trying to create a expense claim app, i have created a form where a user can claim a expense ,when the admin Logs in the following webpage in the picture appears and the webpages iterates all the claims that have claim_status == Null, i want the admin to be able to accept or reject the claim from the dropdown and it to update the value for that object in the database and webpage to refresh and that claim showing no more
I have given a initial value of Null for the ExpenseClaim model and when user fills the expense claim form he cannot see the claim_status field
please see my models
class ExpenseClaim(models.Model):
reference_number = models.AutoField(primary_key=True)
employee_name = models.CharField(max_length=150)
employee_ID = models.CharField(max_length=150)
claim_initiating_date = models.DateTimeField(auto_now=True)
invoice_date = models.DateField()
invoice_location = models.CharField(max_length=150)
biller_name = models.CharField(max_length=150)
invoice_category = models.CharField(max_length=150)
price = models.DecimalField(decimal_places=2, max_digits=10, null=False , default=0.00)
GST = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
CGST = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
IGST = models.DecimalField(decimal_places=2, max_digits=10, null=False , default=0.00)
Total_amount = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
mode_of_payement = models.CharField(max_length=20)
Payment_reference = models.BooleanField()
invoice = models.FileField()
claim_status = models.CharField(default=None , max_length=10)
payment_status = models.CharField(default= None , max_length=10)
Following is my models field i tried to create a new form but that just creates a new object in the database i want to update the existing one
invoice_category_choices =[
('food',"food"),
('travel',"travel"),
('accodmodation',"accomodation"),
('fuel',"fuel"),
# ('others',"others"),
]
claim_status_choices = [
('accepted' , 'accepted'),
('rejected' , 'rejected')
]
payment_status_choices =[
('paid' , 'paid'),
('notpaid' , 'notpaid')
]
class ExpenseClaimForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
exclude = [
"employee_name",
"employee_ID",
"claim_status",
"payment_status"
]
widgets = {
'invoice_date': forms.DateInput(format=('%m/%d/%Y'), attrs={'class':'form-control', 'placeholder':'Select a date', 'type':'date'}),
'invoice_category':forms.Select(choices= invoice_category_choices),
'claim_status':forms.Select(choices= claim_status_choices)
}
class ClaimStatusForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
fields = [
"claim_status",
]
widgets = {
'claim_status':forms.Select(choices= claim_status_choices)
}
forms.py
class ClaimStatusForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
fields = [
"claim_status",
]
widgets = {
'claim_status':forms.Select(choices= claim_status_choices)
}
views .py
def admin_update_view(request , reference_number):
post = get_object_or_404(ExpenseClaim , reference_number=reference_number)
form = ClaimStatusForm(instance=post)
if request.method == 'POST':
post = get_object_or_404(ExpenseClaim , reference_number=reference_number)
form = ClaimStatusForm(request.POST)
if form.is_valid():
claim_status = form.cleaned_data.get('claim_status')
post.claim_status = claim_status
post.save()
return redirect('/admin/')
context = { "form":form , "initialize_context" : initialize_context(request)}
return render(request , 'graphauth/adminupdate.html' , context)
urls.py
path('adminupdate/<int:reference_number>', views.admin_update_view , name='adminupdate'),
admin.html
update

how to filter foreign key in django form without passing foreign key value?

I have created two models in my django project AddStudent and Fee Entry as shown below.
models.py
class AddStudent(models.Model):
enrollment_no = models.BigIntegerField(primary_key=True)
student_name = models.CharField(max_length=500,null=True)
gender = models.CharField(max_length=1,choices=GENDER_CHOICES)
course = models.ForeignKey(CourseMaster, on_delete=models.DO_NOTHING, null=True)
category= models.ForeignKey(CatMaster, on_delete=models.DO_NOTHING, null=True)
admission_year = models.IntegerField(('year'), choices=YEAR_CHOICES, default=datetime.datetime.now().year)
college = models.ForeignKey(CollegeMaster, on_delete=models.DO_NOTHING, null=True)
branch = models.ForeignKey(BranchMaster,on_delete=models.DO_NOTHING, null=True)
current_semester = models.IntegerField(null=True)
address = models.CharField(max_length=1000,null=True)
city = models.CharField(max_length=100,null=True)
district = models.CharField(max_length=100,null=True)
state = models.CharField(max_length=100,null=True)
student_contact = models.BigIntegerField()
parent_contact = models.BigIntegerField()
def get_absolute_url(self):
return reverse('add_student:index')
def __str__(self):
return str(self.enrollment_no) + ' - ' + self.student_name
class FeeEntry(models.Model):
student = models.ForeignKey(AddStudent,on_delete=models.DO_NOTHING)
fee_detail = models.ForeignKey(FeeMaster,on_delete=models.DO_NOTHING)
fee_sem = models.IntegerField(null=True)
payment_date = models.DateField(("Date"), default=datetime.date.today)
pay_method = models.BooleanField(choices=BOOL_CHOICES)
cheque_no = models.CharField(max_length = 100, null=True, blank=True)
bank_name = models.CharField(max_length = 200, null=True, blank=True)
def __str__(self):
return str(self.id) + ' - ' + str(self.student) + ' - ' + self.student.student_name
Now when user search particular student for example student id = 1 than student profile page will open and there is another button addfee. My problem is when user click on add fee all 500 student list is appear in dropdown list. i want to create fee for searched student only.
forms.py
from django import forms
from .models import FeeEntry, AddStudent
from bootstrap_modal_forms.mixins import PopRequestMixin, CreateUpdateAjaxMixin
class FeeForm(PopRequestMixin, CreateUpdateAjaxMixin, forms.ModelForm):
class Meta:
model = FeeEntry
fields = ['student', 'fee_detail', 'fee_sem', 'payment_date', 'pay_method','cheque_no','bank_name']
above is my forms.py file where field 'student' will generate all 500 student list. I want only selected student for example enrollment_no=1 when user is on enrollment_no 1's page.
views.py
class FeeCreateView(PassRequestMixin, SuccessMessageMixin,
generic.CreateView):
template_name = 'add_student/create_fee.html'
form_class = FeeForm
success_message = 'Success: Book was created.'
success_url = reverse_lazy('add_student:detail')
urls.py
path('create/<int:pk>', views.FeeCreateView.as_view(), name='create_fee'),
Can anyone tell me what changes are required in this code? or can you share link of similar example like this?
The FeeForm does not know which student you want to relate it with. Because of that, it is showing you a dropdown asking which student you want to assign to the FeeEntry instance.
Remove 'student' from the form and send the form to the view. when the user submits the form, use the form_valid (form.is_valid if you are using FBV) method to assign the student to the fee_entry instance.
def form_valid(self, form):
fee_entry = form.save(commit=False)
fee_entry.student = AddStudent.objects.get(id=self.kwargs['student_id'])
fee_entry.save()
Also make sure to send the student_id in the url. You can even send it as a POST parameter(check out how to retrieve parameter from a POST request) using a hidden field in the form.

Compare two different SOQL queries

I am new to salesforce and I am stuck with a situation here.
I have a class which is scheduled every hour. I hit an account with the below code and an email is sent out to MAROPOST (Marketing automation tool). When this happen I want to track the Account and create a case or a log which says Welcome Email is sent so that I don't hit the same Account again.
Please help. Below is the working class. Please help
public class PD_WelcomeMaroPost {
public static string sendEmailThroughMaro(string myInpEmail) {
string successContacts = '';
string failureContacts = '';
// SQL to fetch FBO who Joined Today
list<Account> conts = new list<Account> ([SELECT name, Email_FLP_com__c,
(SELECT Id
FROM Stripe_Subscriptons__r
WHERE Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false
LIMIT 1)
from account
where ID IN (
select Distributor__c
from Stripe_Subscripton__c
where Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false)
AND Email_FLP_com__c != NULL
LIMIT 100]);
system.debug('>>>>>>>>>>' + conts);
overallEmail myEmail = new overallEmail();
List<Stripe_Subscripton__c> subsToUpdate = new List<Stripe_Subscripton__c>();
for(Account c : conts){
myEmail.email.campaign_id = 172;
myEmail.email.contact.Email = c.Email_FLP_com__c;
myEmail.email.contact.first_name = c.name;
/**MAp<String, String> tags = new Map<String, String>();
tags.put('firstName', c.name);
myEmail.email.tags = tags;**/
system.debug('#### Input JSON: ' + JSON.serialize(myEmail));
try{
String endpoint = 'http://api.maropost.com/accounts/1173/emails/deliver.json?auth_token=j-V4sx8ueUT7eKM8us_Cz5JqXBzoRrNS3p1lEZyPUPGcwWNoVNZpKQ';
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('POST');
req.setHeader('Content-type', 'application/json');
req.setbody(JSON.serialize(myEmail));
Http http = new Http();
system.debug('Sending email');
HTTPResponse response = http.send(req);
system.debug('sent email');
string resultBodyGet = '';
resultBodyGet = response.getBody();
system.debug('Output response:' + resultBodyGet);
maroResponse myMaroResponse = new maroResponse();
myMaroResponse = (maroResponse) JSON.deserialize(resultBodyGet, maroResponse.class);
system.debug('#### myMaroResponse: ' + myMaroResponse);
if(myMaroResponse.message == 'Email was sent successfully')
successContacts = successContacts + ';' + c.Email_FLP_com__c;
else
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
}
catch (exception e) {
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
system.debug('#### Exception caught: ' + e.getMessage());
}
c.Stripe_Subscriptons__r[0].Welcome_Email__c = true;
subsToUpdate.add(c.Stripe_Subscriptons__r[0]);
}
Update subsToUpdate;
return 'successContacts=' + successContacts + '---' + 'failureContacts=' + failureContacts;
}
public class maroResponse {
public string message {get;set;}
}
public class overallEmail {
public emailJson email = new emailJson();
}
public class emailJson {
public Integer campaign_id;
public contactJson contact = new contactJson();
// Public Map<String, String> tags;
}
public class contactJson {
public string email;
public string first_name;
}
}
You're making a callout in a loop, there's governor limit of max 100 callouts. See Limits class to obtain current & max numbers programatically rather than hardcoding it.
Other than that it should be pretty simple change. First add your filter to the query and add a "subquery" (something like a JOIN) that pulls the related list of subscriptions
list<Account> conts = new list<Account> ([SELECT name, Email_FLP_com__c,
(SELECT Id
FROM Stripe_Subscriptions__r
WHERE Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false
LIMIT 1)
from account
where ID IN (
select Distributor__c
from Stripe_Subscripton__c
where Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false)
AND Email_FLP_com__c != NULL
LIMIT 100]);
Then it's just few lines more
List<Stripe_Subscription__c> subsToUpdate = new List<Stripe_Subscription__c>();
for(Account a : conts){
// do your maropost code here
a.Stripe_Subscriptions__r[0].Welcome_Email__c = true;
subsToUpdate.add(a.Stripe_Subscriptions__r[0]);
}
update subsToUpdate;
Of course you might want to set that checkbox to true only if callout went OK ;)
After reading your code, I don't see where you tried to accomplish this. If you post your attempt I'd be glad to help fix it.
Instead I'll give you different logic for what you are trying to do.
1.) create new checkbox field
2.) in batch query where box is not checked
3.) send email
4.) check checkbox
to answer your comment here is some sample code, you will need to fix it yourself, i am just making temp names
for(sobjectname gg:[your query]){
Send email;
gg.checkbox = checked;
update gg;
}
it'd be better to make it bulkified though
list<yourSObject> tobeupdated = new list<yourSObject>([Your query]);
for(yourSObject gg: tobeupdated){
send email;
gg.checkbox = true;
}
update tobeupdated;

GAE python: Get and post request working without submitting a post request through a form

This is a continuation of this question
What follows is an abbreviated version of the original code. I tried to include the most relevant parts and left out the part of the script used by a cron job which updates the Datastore with values.
Then, in the sendFollowUp() handler, a second cron job queries the Datastore for these values, then uses a push task queue to send these values as parameters which are ultimately used in a REST API call to another service that sends people(entities) in the Datastore an email.
What I can't figure out is how to follow-up a get request with a post request in the same handler without submitting a post request through a form. This needs to happen within the sendFollowUp handler. Most of the examples I have found include submitting a form. However, I don't want to do that. I just want it to work automatically with the cron job and task queue.
import webapp2
import datetime
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.api import taskqueue
import jinja2
import os
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class emailJobs(db.Model):
""" Models an a list of email jobs for each user """
triggerid = db.StringProperty() #Trig id
recipientid_po = db.StringProperty() # id
recipientlang = db.StringProperty() #Language
fu_email_sent = db.DateTimeProperty()
fuperiod = db.IntegerProperty() # (0 - 13)
fu1 = db.DateTimeProperty()
fu2 = db.DateTimeProperty()
#classmethod
def update_fusent(cls, key_name, senddate):
""" Class method that updates fu messages sent in the GAE Datastore """
emailsjobs = cls.get_by_key_name(key_name)
if emailsjobs is None:
emailsjobs = cls(key_name=key_name)
emailsjobs.fu_email_sent = senddate
emailsjobs.put()
def timeStampFM(now):
d = now.date()
year = d.year
month = d.month
day = d.day
t = now.time()
hour = t.hour
minute = t.minute + 5
second = t.second
today_datetime = datetime.datetime(year, month, day, hour, minute, second)
return today_datetime
class MainPage(webapp2.RequestHandler):
""" Main admin login page """
def get(self):
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
urla = '/'
url_admin = ""
if users.is_current_user_admin():
url = users.create_logout_url(self.request.uri)
urla = "_ah/admin/"
url_admin = 'Go to admin pages'
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
template_values = {
'url': url,
'url_linktext': url_linktext,
'url_admin': url_admin,
'urla': urla,
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class sendFollowUp(webapp2.RequestHandler):
""" Queries Datastore for fu dates that match today's date, then adds them to a task queue """
def get(self):
now = datetime.datetime.now()
now_dt = now.date() #today's date to compare with fu dates
q = emailJobs.all()
q.filter('fuperiod >', 0)
q.filter('fuperiod <', 99)
for part in q:
guid = str(part.recipientid_po)
lang = str(part.recipientlang)
trigid = str(part.triggerid)
if part.fuperiod == 1:
fu1rawdt = part.fu1
fu1dt = fu1rawdt.date()
if fu1dt == now_dt:
follow_up = '1'
if part.fuperiod == 2: # the values go up to 12 in the original code
fu2rawdt = part.fu2
fu2dt = fu2rawdt.date()
if fu2dt == now_dt:
follow_up = '2'
if follow_up != None:
taskqueue.add(queue_name='emailworker', url='/emailworker', params={'guid': guid,
'fu': follow_up,
'lang': lang,
'trigid': trigid,
})
self.redirect('/emailworker')
class pushQueue(webapp2.RequestHandler):
""" Sends fu emails, updates the Datastore with datetime sent """
def store_emails(self, trigid, senddate):
db.run_in_transaction(emailJobs.update_fusent, trigid, senddate)
def get(self):
fu_messages = {'1': 'MS_x01',
'2': 'MS_x02',
# the values go up to 12 in the original code
}
langs = {'EN': 'English subject',
'ES': 'Spanish subject',
}
fu = str(self.request.get('fu'))
messageid = fu_messages[fu]
lang = str(self.request.get('lang'))
subject = langs[lang]
now = datetime.datetime.now()
senddate = timeStampFM(now)
guid = str(self.request.get('guid'))
trigid = str(self.request.get('trigid'))
data = {}
data['Subject'] = subject
data['MessageID'] = messageid
data['SendDate'] = senddate
data['RecipientID'] = guid
# Here I do something with data = {}
self.store_emails(trigid, senddate)
app = webapp2.WSGIApplication([('/', MainPage),
('/cron/sendfu', sendFollowUp),
('/emailworker', pushQueue)],
debug=True)
I'm not sure I really understand your question, but can't you just create a POST request with the requests module?
Post Requests
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
Also for easy task use have you seen the deferred library?
The deferred library lets you bypass all the work of setting up dedicated task handlers and serializing and deserializing your parameters by exposing a simple function, deferred.defer(). To call a function later, simply pass the function and its arguments to deferred.defer
Link

Resources