send email on model create - django - django

I want to send an email automatically when I create an invoice. Is that possible? What I'm after. I have a invoice model and I put send_email code in it "def save(self):", I'm making perfex CRM invoice system, so I'm using the foregin key in invoice model to get a customer, but whenever I create new invoice it says "The invoices “INV-b066” was added successfully." but in invoice model it shows nothing like it's empty model I even tried to open invoice using index number and restarted the server and migrations stuff and it didn't worked but if I remove def save(self): function it works perfectly fine I'm trying to send an email automatically on model create
Customer model
class Customers(models.Model):
Your_Name = models.CharField(max_length=220)
Email_Address = models.EmailField(max_length=220)
Profession = models.CharField(max_length=220)
phone = PhoneNumberField(unique=True)
No_of_Persons = models.IntegerField()
Packages = models.CharField(choices=PAKAGES, max_length=100)
Address = models.CharField(max_length=220)
City = models.CharField(choices=CITIES, max_length=10)
Time = models.CharField(choices=TIME, max_length=10)
Date = models.DateTimeField()
Message = models.TextField()
def __str__(self):
return f'{self.Your_Name}'
Invoice model
class Invoice(models.Model):
Customer = models.ForeignKey(Customers, on_delete=models.CASCADE)
Invoice_Number = models.CharField(default=inv_num, max_length=10)
Recurring = models.CharField(choices=Recurrings, max_length=12)
Invoice_date = models.DateField()
Due_date = models.DateField()
Packages = models.CharField(choices=PAKAGES, max_length=100)
Package_name = models.CharField(max_length=50)
Package_description = models.TextField()
Package_Quantity = models.IntegerField()
Package_Price = models.IntegerField()
def __str__(self):
return f'{self.Invoice_Number}'
def save(self):
send_mail(
'Subject',
'message.',
'email#example.com',
['*****#gmail.com'],
fail_silently=False,
)

You have to actually save the invoice like this:
def save(self):
send_mail(
'Subject',
'message.',
'email#example.com',
['*****#gmail.com'],
fail_silently=False,
)
return super(Invoice, self).save()
Also as a part of suggestion it is better to send email as separate task or service, you can use django signals or celery for that.

Related

Filter and get all the customers who had brought the authors other contents to send the notification when new content is added

I want to Filter and get all the customers who had brought the authors other contents to send the notification when new content is added This works on queryset I know but I'm Confused on how to do that. If anyone please share.
Here are my models
content:
class Content(models.Model):
title = models.CharField(max_length=1000)
Author = models.ForeignKey('User',on_delete=models.CASCADE)
slug = AutoSlugField(populate_from='title', unique=True, null=False)
cover = models.ImageField(upload_to='course', default='nocover.jpg')
catogary = models.ForeignKey(Category, on_delete=models.RESTRICT)
description = models.TextField(max_length=2000, null=True, blank=True)
requirements = models.TextField()
price = models.FloatField()
language = models.ForeignKey(Language, on_delete=models.RESTRICT)
Puchased content
class PurchasedContent(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
course = models.ForeignKey(Course, blank=True, related_name='course')
I want all the list of Customers email who had brought a particular Authors course
the Author will be authenticated while adding. We'll get the Author as request.user
Here is sample ListCreateAPIView in django rest Framework
class createlistcontentview(generics.ListCreateAPIView):
permission_classes = [TokenHasReadWriteScope]
queryset = Content.objects.all()
serializer_class = ContentSerializer
def perform_create(self, serializer):
#Here I want to get a list of mails to create a Function that sends mall
serializer.save(author=self.request.user)
So what you can do is use a signal to send the email to the users whenever a content is created like this:
from django.dispatch import receiver
# models.py
#receiver(models.signals.post_save, sender=Content)
def send_email(sender, instance:Content, created, **kwargs):
if created:
# import and use your email helper here
# since the related name you chose for the purchased_content course is a little confusing I changed it to `purchased_content`
purchases = instance.course.purchased_content.all()
send_email(users=[user.email for user in purchases])
return

django checkbox select multiple models

Hi I have the following django model:
class Issue(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField(auto_now=True)
assignee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='assignee')
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner', null=True, blank=True)
description = models.TextField()
state = models.IntegerField(choices=STATUS_CHOICES, default=1)
priority = models.IntegerField(choices=RELEVANCE_CHOICES, default=2)
expired_date = models.DateField(auto_now=False, null=True, blank=True)
and a form which allow a user to create an Issue instance:
class IssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ('title', 'description', 'assignee', 'state', 'priority', 'expired_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].label = "Titolo"
self.fields['description'].label = "Descrizione"
self.fields['state'].label = "Stato"
self.fields['priority'].label = "Priorità"
self.fields['expired_date'].label = "Termine"
self.fields['expired_date'].widget.attrs.update({'class': 'datepicker'})
self.fields['assignee'] = forms.MultipleChoiceField(
choices=self.fields['assignee'].choices,
widget=forms.CheckboxSelectMultiple,
label=("Assegnatario")
)
def clean(self):
cleaned_data = super().clean()
user_id = [i for i in cleaned_data['assignee']]
cleaned_data['assignee'] = [User.objects.get(id=i) for i in user_id]
return cleaned_data
I render this form and the field assignee is a checkbox.
I would like to be able to choose several assignee for the same issue, but I got an error because the Issue model expect just one User instance
How can I modify my model Issue in order to get more than one user ?
Thanks
you can create a new class and name it Issue_Instance where every Issue Object can have an assignee as a foreign key the problem that the relation is one to many because you have to choose more than one assignee and Django doesn't support the idea of having Array or List of Foreign Keys(I don't know any frame works that do :=) ) so I would suggest creating a new class or make the foreign key relation one-to-many key field read about it it will be very useful to solve your problem

While saving Django getting "This choice is not one of the available choices"

I am trying to save a form which have ForeignKey (purchaseContractID).Here is my contract Model
class contracts(models.Model):
productDetailID=models.ForeignKey('Inventory.productDetails',related_name='+',on_delete=models.CASCADE,verbose_name='Select Product',default=None)
supplierID=models.ForeignKey(suppliers,on_delete=models.CASCADE,verbose_name='Select Supplier',default=None)
totalUnits=models.IntegerField(verbose_name='Total Units',editable=False,default=None)
ratePerUnit=models.IntegerField(verbose_name='Rate Per Unit',default=None)
saleTax=models.IntegerField(verbose_name='Sale Tax',default=None)
incomeTax=models.IntegerField(verbose_name='Income Tax',default=None)
saleTaxwithHeld=models.IntegerField(verbose_name='Sale Tax with Held',default=None)
startDate=models.DateField(verbose_name='Start Date',default=None)
endDate=models.DateField(verbose_name='End Date',default=None)
manulContractNumber=models.IntegerField(verbose_name='Manul Contract Number',default=None)
paymentDays=models.IntegerField(verbose_name='Payment Days',default=None)
remarks=models.CharField(verbose_name='Remarks',max_length=100,default=None)
dateOfEntry=models.DateField(editable=False,default=datetime.now())
def __str__(self):
return str(self.productDetailID.name)
here is my inventoryIn Model which foreignKey of PurchaseContract
class inventoryIn(models.Model):
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)
purchaseContractID=models.ForeignKey('Purchase.contracts',on_delete=models.CASCADE,verbose_name='Contract ID')
unitsIn=models.IntegerField(verbose_name='Enter No of Bags')
MYCHOCIES = (('orginal', 'ORGINAL'), ('dummy', 'DUMMY'))
doType = models.CharField(blank=True, choices=MYCHOCIES, verbose_name='Select DO Type', max_length=20)
doID=models.IntegerField(verbose_name='Do No')
doImage=models.ImageField(upload_to='doImage/%Y/%m/%d',verbose_name='Do Image')
invoiceID=models.IntegerField(verbose_name='Invoice No')
invoiceImage=models.ImageField(upload_to='inventoryIn/%Y/%m/%d')
agingDate=models.DateField(verbose_name='Receiving Date')
labReportImage = models.ImageField(upload_to='labReportImage/%Y/%m/%d', blank=True,verbose_name='Lab Report Image')
enterPaymentDays = models.IntegerField(verbose_name='Enter Payment Days', blank=True, default=None)
dateOfEntry=models.DateField(default=datetime.now())
def __str__(self):
return self.supplierID
here is my admin.py where i am adding admin form and also adding a js that add some fields dynamical.
class inventoryInAdmin(admin.ModelAdmin):
fields = ['purchaseContractID','unitsIn','doType','doID','doImage','invoiceID','invoiceImage','agingDate','labReportImage','enterPaymentDays']
class Media:
js = ('js/addInventory.js',)
admin.site.register(inventoryIn,inventoryInAdmin)
it is not allowing me to submit form and giving me error "Select a valid choice. That choice is not one of the available choices."
I have resolved this issue by adding the save method at InventoryIn Model.
class inventoryIn(models.Model):
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)
purchaseContractID=models.ForeignKey('Purchase.contracts',on_delete=models.CASCADE,verbose_name='Contract ID')
unitsIn=models.IntegerField(verbose_name='Enter No of Bags')
MYCHOCIES = (('orginal', 'ORGINAL'), ('dummy', 'DUMMY'))
doType = models.CharField(blank=True, choices=MYCHOCIES, verbose_name='Select DO Type', max_length=20)
doID=models.IntegerField(verbose_name='Do No')
doImage=models.ImageField(upload_to='doImage/%Y/%m/%d',verbose_name='Do Image')
invoiceID=models.IntegerField(verbose_name='Invoice No')
invoiceImage=models.ImageField(upload_to='inventoryIn/%Y/%m/%d')
agingDate=models.DateField(verbose_name='Receiving Date')
labReportImage = models.ImageField(upload_to='labReportImage/%Y/%m/%d', blank=True,verbose_name='Lab Report Image')
enterPaymentDays = models.IntegerField(verbose_name='Enter Payment Days', blank=True, default=None)
dateOfEntry=models.DateField(default=datetime.now())
def __str__(self):
return str(self.supplierID)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
from Purchase.models import contracts,suppliers
contract = contracts.objects.values('supplierID', 'productDetailID').filter(id=self.purchaseContractID.id)
supplier=contract[0].get("supplierID")
product=contract[0].get("productDetailID")
self.supplierID=suppliers.objects.get(id=supplier)
self.productID=products.objects.get(productDetailsID=product)
super(inventoryIn,self).save()
and i also had made my two fields editable=False
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)

How do create an object that has multiple objects in django rest framework via a POST method using class based views

I have created an Employee class below in my models. The Employee class has multiple Foreign Keys such as User,Contact,Skill etc. I would like to make it possible that when I create an Employee all the other objects will be created plus including the User object. I have implemented a POST method in my view that does this but I feel like my code is too long. How do I make a single POST to create all these multiple objects? An illustration using Managers will be also nice.
class Employee(models.Model):
"""
Model, which holds general information of an employee.
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL,
related_name='employees', null=True)
company = models.ForeignKey(
'hr.Company',
verbose_name='Company',
related_name='companies',
null=True, blank=True,
)
hr_number = models.CharField(
verbose_name='HR number',
blank=True, null=True,
max_length=20, unique=True
)
identification_number = models.CharField(
verbose_name='ID Number',
blank=True, null=True,
max_length=20, unique=True
)
contract_type = models.ForeignKey(Contract)
tax_id_number = models.CharField(
max_length=20, null=True, verbose_name='Tax ID', blank=True, unique=True)
skill = models.ForeignKey(Skill)
# joining can be added in user profile
joining_date = models.DateField(null=True, verbose_name="Joining Date")
job_title = models.ForeignKey(
Job, related_name='job_titles', null=True, blank=True, help_text='Default Permission for different modules in Portal depends upon employee\'s Designation.')
department = models.ForeignKey(
Department, related_name='department', null=True, blank=True, on_delete=models.SET_NULL)
is_manager = models.BooleanField(default=False)
# leave_count = models.IntegerField(default=0)
active = models.BooleanField(default=True)
In my views I have have implemented the POST method below:
class AddEmployee(APIView):
# permission_classes = (permissions.DjangoObjectPermissions,)
# serializer_class = EmployeeSerializer
"""
{
"user":null,
"new_user":{
"first_name":"John",
"last_name":"Wane",
"username":"Wai",
"email":"jwane#gmail.com",
"password":"123"
},
"company":1,
"department":1,
"identification_number":"234567",
"hr_number":"GH/099/2017",
"tax_id_number":"AEEEEEE",
"joining_date":"2018-04-02",
"job_title":null,
"new_job":{
"name":"Doctor",
"min_salary":50000,
"max_salary":50000
}
}
"""
def post(self, request, format=None):
try:
company = Company.objects.get(id=request.data['company'])
department = Department.objects.get(id=request.data['department'])
try:
c_user = User.objects.get(id=request.data['user'])
except:
new_user = request.data['new_user']
c_user = User.objects.create(first_name=new_user['first_name'],
last_name=new_user['last_name'],
username=new_user['username'],
email=new_user['email'],
password=new_user['password'])
try:
job_title = Job.objects.get(id=request.data['job_title'])
except:
new_job = request.data['new_job']
if new_job:
job_title = Job.objects.create(
name=new_job['name'],
min_salary=new_job['min_salary'],
max_salary=new_job['max_salary']
)
employee = Employee.objects.create(
user=c_user,
company=company,
department=department,
job_title=job_title,
hr_number=request.data['hr_number'],
identification_number=request.data['identification_number'],
tax_id_number=request.data['tax_id_number'],
joining_date=request.data['joining_date']
)
except Exception as e:
print(e)
return Response(status=status.HTTP_201_CREATED)
DRF do not manage nested serialiser or this kind of things. that said, you can simplify your code using Model.objects.get_or_create
example :
try:
job_title = Job.objects.get(id=request.data['job_title'])
except:
new_job = request.data['new_job']
if new_job:
job_title = Job.objects.create(
name=new_job['name'],
min_salary=new_job['min_salary'],
max_salary=new_job['max_salary']
)
# can be write with get_or_create:
job_defaults = {
'name': new_job['name'],
'min_salary': new_job['min_salary'],
'max_salary': new_job['max_salary']
}
Job.objects.get_or_create(name=new_job['name'],defaults=job_defaults)
You can also use Model Serializer to manage filtering + validating + save sub object
examples :
# serializers.py
class JobSerializer(serializers.ModelSerializer):
class Meta:
model = Job
fields = ('id', 'name', 'min_salary', 'max_salary')
# inside views.py's post method
try:
job_title = Job.objects.get(id=request.data['job_title'])
except:
JobSerializer(data=new_job).save()
see also:
DRF documentation about writable nested serializers
External extension to help with nested serializers

Modelserializer using kwargs to get FK object

I'm creating a Django (1.8) webapp that saves racing laptimes and scoreboards. The database is populated using an API built using Django Rest Framework. It's the first time I'm trying to build a proper api using rest framework.
A quick overview of the models:
Event, A racing event/weekend
Session, A single race/practice/quali - FK Event
Car, A car taking part in a session - FK Session
Lap, Laps for specific car - FK Car
The Event is created manually, but the rest is supposed to be "dynamic" (get or create)
Right now I'm trying to create a new car using my API, but I'm stuck. To get the cars event and session I'm trying to use the url;
/api/results/skrotbilsracet-29042016/r1/cars/
The idea is to post data to this url and "get or create" a new car object.
To get the correct session object for the new car session FK, I need to use a custom function that takes the kwargs and tries to find the session.
The more I read about how to solve this, the more confused I get.
Could someone push me in the right direction?
This is my latest attempt at solving this, which just gives me "{"session":["This field is required."]}"
models.py
class Session(models.Model):
session_types = (
('p', 'Practice'),
('q', 'Qualification'),
('r', 'Race')
)
event_id = models.ForeignKey(Event, related_name='sessions')
name = models.CharField(max_length=2, blank=True)
current_session = models.BooleanField(default=True)
session_type = models.CharField(max_length=2,
choices=session_types)
started = models.DateTimeField(auto_now_add=True)
ended = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['started']
def save(self):
if not self.name:
# Get number of sessions
session_count = Session.objects.filter(event_id=self.event_id)\
.filter(session_type=self.session_type)\
.count()
session_count += 1
self.name = self.session_type + str(session_count)
super(Session, self).save()
def __unicode__(self):
string = self.started.strftime("%d-%m-%Y %H:%M") + ' - '
string += self.name.upper()
return(string)
class Car(models.Model):
session = models.ForeignKey(Session, related_name='cars')
number = models.IntegerField()
full_name = models.CharField(max_length=256, blank=True)
short_name = models.CharField(max_length=256, blank=True)
race_class = models.CharField(max_length=50, blank=True)
best_lap = models.IntegerField(blank=True, null=True)
best_lap_time = models.CharField(max_length=20, blank=True)
best_sector1 = models.CharField(max_length=20, blank=True)
best_sector2 = models.CharField(max_length=20, blank=True)
best_sector3 = models.CharField(max_length=20, blank=True)
best_speed = models.IntegerField(blank=True, null=True)
pitstops = models.IntegerField(blank=True, null=True)
total_time = models.CharField(max_length=20, blank=True)
transponder = models.CharField(max_length=50, blank=True)
apiUrls.py
urlpatterns = [
url(r'^raceslug/$', raceSlugView.as_view(), name='race-slug'),
url(r'^events/$', eventsView.as_view(), name='event-list'),
url(r'^session/$', getSessionView.as_view(), name='session-pk'),
url(r'^(?P<event_id>[a-z0-9\-]+)/$', eventView.as_view(), name='event-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/$', sessionView.as_view(), name='session-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/cars/$', carsView.as_view(), name='car-list'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/(?P<number>[0-9]+)/$', carView.as_view(), name='car-detail'),
]
urlpatterns = format_suffix_patterns(urlpatterns)
api.py
class carsView(generics.ListCreateAPIView):
serializer_class = carSerializer
def get_session(self, event_id, name):
print('Getting session')
# Get event object
try:
event = Event.objects.get(event_id=event_id)
print('Found event')
except ObjectDoesNotExist:
print('Did not find event')
return
# Get session object
try:
session = event.sessions.get(name=name)
print('Found session: ', session)
return session
except ObjectDoesNotExist:
print('Did not find session')
return
def get_queryset(self):
print('Getting queryset')
print('event_id: ' + self.kwargs['event_id'])
print('name: ' + self.kwargs['name'])
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
return(Car.objects.filter(session=session.pk))
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
class Meta:
model = Car
fields = (
'session',
'number',
'full_name',
'short_name',
'race_class',
'best_lap',
'best_lap_time',
'best_sector1',
'best_sector2',
'best_sector3',
'best_speed',
'pitstops',
'total_time',
'transponder',
'laps')
Solution:
This is what I actually changed to get it working.
api.py
from rest_framework.serializers import ValidationError
class carsView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
number = self.request.POST.get('number')
car = session.cars.filter(number=number)
if car.exists():
raise ValidationError('Car already exists')
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
session = serializers.StringRelatedField(required=False)
...
I see that you're creating your session ID there:
def get_queryset(self):
...
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
return(Car.objects.filter(session=session.pk))
Then you don't need it in a serializer, only in a model. So you can set it a snot required in a serializer, but it will still be required in a model.
I guess this answer could help you: Django REST Framework serializer field required=false