How to get email from usercusomer for followers - django

I want to send an email to each follower after creating the item. But I don't know how to get this field from Models, and also I don't know how to send each follower to relate following.
models.py
class Book(models.Models):
title = models.CharField(max_length=255)
author = models.ForeignKey(
"users.CustomUser", on_delete=models.SET_NULL, null=True
)
# This is my try
#But it doesn't work
#hook(AFTER_CREATE)
def send_followers(self):
user = Followers.objects.all()
followers_email = CustomUser.objects.filter(
followers__follower__in=, followers__following=self.author.profile)
if CustomUser.objects.filter(
followers__follower__in=CustomUser.objects.only(
'followers__follower'),
followers__following=self.author.profile
).exists():
send_mail(
"Article published",
'%s' % (
followers_email
),
"nikitaalexnazarov#yandex.ru",
[self.author.email],
fail_silently=False,
)
else:
pass
class CustomUser(AbstractUser):
gender = models.ForeignKey(
"Gender", on_delete=models.CASCADE, blank=True, null=True
)
class Followers(models.Model):
follower = models.ForeignKey(
"users.CustomUser", on_delete=models.CASCADE, null=True, blank=True)
following = models.ForeignKey(
"Profile", on_delete=models.CASCADE, null=True, blank=True)
class Profile(models.Model):
slug = models.SlugField(unique=True)
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)

Your requirement can be fulfilled with signals. In Django, signals are used to perform certain actions based on some events. In your case, you want to send emails to all the followers of the author whenever a new book is created. Code that sends mails can be implemented in receivers. post_save signal will be triggered whenever a new row is created in the Book model. The corresponding signal will be received by the 'send_mail' receiver and will be executed.
signals.py
from django.dispatch import receiver
#reciever(post_save, sender="Book")
def send_mail(sender, instance, **kwargs):
# get the user model row of the author. Since author field is in M2One relationship with CustomUser, we can access the id of the user.
user_obj = instance.author
# ProFile model is in One2One relationship with CustomUser. Get the profile instance/row corresponding to the user_obj.
profile_obj = user_obj.profile
followers_list = Followers.objects.filter(following=profile_obj)
#followers_list will be having a list of all the followers to whom mail can be sent. You can retrieve the email of the followers present in followers_list.
apps.py
from django.apps import AppConfig
class AppNameConfig(AppConfig):
name = 'AppName'
def ready(self):
import signals over here

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

Why does Django not find a field added to the AbstractBaseUser

I've inherited from the AbstractBaseUser as follows:
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Meta
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=40, unique=True) # equals to email
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
So each User is linked to one and only one Customer.
Now within a view I want to access the instance of the current logged in user within the request object and get the employee_of value to get a queryset that contains all users of that customer.
def render_employees(request):
"""
Renders the employees page of the dashboard
:param request:
:return:
"""
# Return the value for the current site for css specific classes
dashboard_site = 'employees'
# Query the employees
qs_employees = User.objects.filter(employee_of=request.user.employee_of) # doesn't find field
...
However the filter doesn't work because request.user.employ_of doesn't seem to return anything. My IDE even suggests e.g. username, date_joined etc. but not employee_of.
Why's that?
class Customer(models.Model):
"""
A table that stores static data about a customer, usually a legal company
"""
legal_name = models.CharField(max_length=50)
street = models.CharField(max_length=30)
street_number = models.CharField(max_length=3)
def __str__(self):
return self.legal_name
Update:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from applications.customer.models import Customer
from django.conf import settings
BaseUser = settings.AUTH_USER_MODEL
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Relations
user = models.OneToOneField(BaseUser, related_name='user_profile', on_delete=models.CASCADE, null=True) # link to default user model
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True, blank=True)
I linked the user to the default user model via Django admin. However in the view im still not able to access employee_of within request.user
It seems that request.user is a different model. It's User model from django.contrib.auth. https://docs.djangoproject.com/en/4.0/ref/contrib/auth/#django.contrib.auth.models.User.
What you can do about it?
In our app we have UserProfile model that have OnetoOne relation to django User.
You can then store employee_of value there.
class UserProfile(AbstractBaseUser):
user = models.OnetoOneField("auth.User", related_name="user_profile", on_delete=models.CASCADE)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
and then access request.user employees using something like
request.user.user_profile.employee_of

Django - Creating a row in onther table before creating user

I have user, userprofile and company tables.
I want to create a record in company table and then assign the id of the newly created company in the userprofile foreign key before creating the user. I think it can be done using pre_save signal but I am unable to figure how. Please help.
Here's some details as AMG asked:
I have django's builtin user model
a userprofile model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='profile_pics/default.jpeg', upload_to='profile_pics')
bio = models.TextField(blank=True, verbose_name='Biography')
company_name = models.ForeignKey(Company, on_delete=models.CASCADE)
a company model
class Company(models.Model):
name = models.TextField(blank=True, verbose_name="Company Name")
nof = models.IntegerField(verbose_name="No. of Employees")
All three are related user and userprofile has one to one relationship, and userprofile and company has many to one relationship.
I want Company record to be created first and than that new record's reference needs to be put into userprofile.
I think I have made it clear now.
Exactly, you can use pre_save for this. You can just put this in models.py below your defined models.
from django.db.models.signals import pre_save
#receiver(pre_save, sender=Profile) # register your model to the signal pre_save
def my_callback(sender, instance, *args, **kwargs):
if not instance.company_name: # check if instance has a value for company_name
company = Company.objects.create(
name='Test',
nof=1
)
instance.company_name = company
OR
Create a default value through a function.
class Company(models.Model):
name = models.TextField(blank=True, null=True, verbose_name="Company Name") # set blank=true and null=true so you can save an empty instance
nof = models.IntegerField(blank=True, null=True, verbose_name="No. of Employees")
def profile_company_default():
return Company.objects.create()
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='profile_pics/default.jpeg', upload_to='profile_pics')
bio = models.TextField(blank=True, verbose_name='Biography')
company_name = models.ForeignKey(Company, on_delete=models.CASCADE, default=profile_company_default) # add function as default value
EDIT
To edit company after save.
profile = Profile.objects.create(key="value")
profile.company.name = "Company Name"
profile.company.nof = 5
profile.save()

How to change a field that automatically affect other records in Django

How to change a field in a specific record that automatically affect the same field on other records?
Consider the following model:
class AccountUser(models.Model):
ADMIN='A'
USER='U'
USER_PROFILES = (
(ADMIN, 'Admin'),
(USER, 'User'),
)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile = models.CharField(max_length=1,choices=USER_PROFILES,default=USER)
current_account = models.BooleanField(default=True)
def __str__(self):
return format('{} ({})'.format(self.account.name, self.user.username))
This is a many-to-many relation between users and accounts, so users can be in many accounts but every user can have one and only one current account. Then, everytime a new record is created or updated with current_account = True, any other records from the same user should be updated with current_account = False.
I've saw a similar question in Actions triggered by field change in Django, but it is for changes in the same record.
I think that you can achieve this with post_save signals. I hope i understood the logic you mean, but you can simply refactor the post_save staticmethod to achieve your objective.
from django.db.models.signals import post_save
class AccountUser(models.Model):
ADMIN='A'
USER='U'
USER_PROFILES = (
(ADMIN, 'Admin'),
(USER, 'User'),
)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile = models.CharField(max_length=1,choices=USER_PROFILES,default=USER)
current_account = models.BooleanField(default=True)
#staticmethod
def post_save(sender, instance):
records = AccountUser.objects.filter(user = instance.user)
for record in records:
record.current_account = True
record.save()
def __str__(self):
return format('{} ({})'.format(self.account.name, self.user.username))
post_save.connect(AccountUser.post_save, sender=AccountUser)

Django 1.11 many to many does not appear in django admin

Hi i have a django model for notification which have a many-to-many relation but nothing appears in django admin ( all fields do not appear)
class Notification(models.Model):
"""send notification model"""
title = models.CharField(max_length=200)
text = models.TextField(null=True, blank=True)
device = models.ManyToManyField(Device, null=True, blank=True)
country = models.ManyToManyField(Country, null=True, blank=True)
sent = models.BooleanField(default=False)
when i open django admin for this model and press add notification this is what happens (nothing appears)
Country and Device Code
class Device(models.Model):
"""Store device related to :model:`accounts.User`."""
user = models.OneToOneField(User, related_name='device', on_delete=models.CASCADE)
model = models.CharField(max_length=200, blank=True, null=True)
player_id = models.CharField(max_length=200, blank=True, null=True)
class Meta:
verbose_name = 'Device'
verbose_name_plural = 'Devices'
def __str__(self):
return self.model
class Country(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
Admin.py
from django.contrib import admin
from .models import Notification
admin.site.register(Notification)
Edit:
Thank you all the problem is solved
The problem was caused by some entries in device model that did have None in the model field so there was a problem displaying it correctly.
According to https://code.djangoproject.com/ticket/2169 :
When a class has a field that isn't shown in the admin interface but
must not be blank, it's impossible to add a new one. You get a cryptic
"Please correct the error below." message with no shown errors. The
error message should probably say something about a hidden field.
Now ManyToManyFields don't need null=True, try removing those statements and see if you get an improvement.
Also, try adding the Country and Device models in admin.py so admin can see them and display them.
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#working-with-many-to-many-models
Define an inline for the many-to-manys in admin.py:
from django.contrib import admin
class DeviceInline(admin.TabularInline):
model = Notification.device.through
class CountryInline(admin.TabularInline):
model = Notification.country.through
class NotificationAdmin(admin.ModelAdmin):
inlines = [
DeviceInline, CountryInline
]
exclude = ("device", "country")