Django check when user created - python

So in any Django project, it is fairly simple to tell if an object has been created by overriding the save method:
def save(self, *args, **kwargs):
created = False
if not self.pk:
created = True
super(ModelName, self).save(*args,**kwargs)
if created:
#do what you want or call a signal
But I need to call a function after a User is created from django.contrib.auth.models.User. I would prefer not to have to actually edit the user model's save method.
How could I go about doing this?
Note:
using pre_save will not work because none of the info from the model will be available, and that is necessary.

You can use post_save signal.
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save)
def do_your_thing(sender, **kwargs):
if sender is User:
if kwargs["created"]:
print kwargs["instance"].password
# do your thing

Related

How can I add a new database entry upon user registration with Django?

I'm starting to learn Django and have a class called Customer in my models.
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
primary_key=True)
cart = models.ManyToManyField(Product)
orders = models.ManyToManyField(Order)
def __init__(self, user):
self.user = user
I'm importing django.contrib.auth to register users to the database, but I would like to also initialize a Customer object upon registration.
I first attempted to override the save() method from the UserCreationForm and initialize a Customer object there:
class UserCreationForm(forms.ModelForm):
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
customer = Customer(user)
customer.save()
if commit:
user.save()
return user
But it did not seem to create a Customer object.
Alternatively, is it better to extend the User class to have the Customer class fields? I initially thought I should keep authentication separate, which is why I created the Customer class.
Might be better if you created a signal instead!
from django.db.models import signals
from django.dispatch import receiver
from django.contrib.auth.models import User
from path.to.models import Customer
#receiver(signals.post_save, sender = User)
def create_customer(sender, instance, created, *args, **kwargs):
if created:
c = Customer(...) #create your customer object
c.save()
and in apps.py, import signals to run it.

Admin side modification django

I have this class In which when I submit a name it goes to admin and only admin can approve this. I want that when admin approve a email automatically should be sent to user.
class myab(models.Model):
generic_name = models.CharField(max_length=50, null=False)
timestamp = models.DateTimeField(auto_now_add=True)
is_approved = models.BooleanField(null=False, default=False)
I only wanted to know how to trigger email code . I have everything else just wanted to understand how to trigger that function when Admin will approve this post.
You could make a listener function to the post-save signal and use a if to check if the instance was approved; read the signal docs for a better understanding.
The signal receiver could look similar to this:
from django.core import mail
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel
#receiver(post_save, sender=MyModel)
def my_handler(sender, instance, created, *args, **kwargs):
...
if instance.is_approved:
mail.send_mail(...)
Highlighting this section of the docs:
Where should this code live?
[...] signal handling [...] code can live
anywhere you like, although it’s recommended to avoid the
application’s root module and its models module [...]
In practice, signal handlers are usually defined in a signals
submodule of the application they relate to [...]

Delete object from database automatically if one field is TRUE

Automatically delete an object from the database if one attribute of the object is TRUE.
I've tried Django Signals, but it didn't help.
class Question(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(max_length=50)
question = models.TextField(max_length=200)
answered = models.BooleanField(default=False)
def __str__(self):
return self.name
If I change the "answered" field to TRUE in Admin Panel, then this object must be automatically deleted from the database.
You will need post_save signals by using something like:
from .models import Question
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Question)
def save_profile(sender, instance, **kwargs):
if instance.answered:
instance.delete()

What is the difference between using post_save signal or do the logic in view

So I have the following code:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import UserProfile
#receiver(post_save, sender=User)
def auto_create_profile(sender, **kwargs):
instance = kwargs['instance']
created = kwargs['created']
if created:
profile = UserProfile(foo=foo)
profile.user = instance
profile.save()
what is the difference between the previous code and creating the profile on register view?
def some_view(request):
#save the user and then
profile = UserProfile(foo=foo, user=user)
profile.save()
With post_save, user profile will be also created when user account is created in other ways, for example:
using manage.py shell console
using django admin
using some other view
using third party packages, like python-social-auth

Populating django field with pre_save()?

class TodoList(models.Model):
title = models.CharField(maxlength=100)
slug = models.SlugField(maxlength=100)
def save(self):
self.slug = title
super(TodoList, self).save()
I'm assuming the above is how to create and store a slug when a title is inserted into the table TodoList, if not, please correct me!
Anyhow, I've been looking into pre_save() as another way to do this, but can't figure out how it works. How do you do it with pre_save()?
Is it like the below code snippet?
def pre_save(self):
self.slug = title
I'm guessing not. What is the code to do this?
Thanks!
Most likely you are referring to django's pre_save signal. You could setup something like this:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.template.defaultfilters import slugify
#receiver(pre_save)
def my_callback(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.title)
If you dont include the sender argument in the decorator, like #receiver(pre_save, sender=MyModel), the callback will be called for all models.
You can put the code in any file that is parsed during the execution of your app, models.py is a good place for that.
#receiver(pre_save, sender=TodoList)
def my_callback(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.title)
you can use django signals.pre_save:
from django.db.models.signals import post_save, post_delete, pre_save
class TodoList(models.Model):
#staticmethod
def pre_save(sender, instance, **kwargs):
#do anything you want
pre_save.connect(TodoList.pre_save, TodoList, dispatch_uid="sightera.yourpackage.models.TodoList")
The pre_save() signal hook is indeed a great place to handle slugification for a large number of models. The trick is to know what models need slugs generated, what field should be the basis for the slug value.
I use a class decorator for this, one that lets me mark models for auto-slug-generation, and what field to base it on:
from django.db import models
from django.dispatch import receiver
from django.utils.text import slugify
def autoslug(fieldname):
def decorator(model):
# some sanity checks first
assert hasattr(model, fieldname), f"Model has no field {fieldname!r}"
assert hasattr(model, "slug"), "Model is missing a slug field"
#receiver(models.signals.pre_save, sender=model, weak=False)
def generate_slug(sender, instance, *args, raw=False, **kwargs):
if not raw and not instance.slug:
source = getattr(instance, fieldname)
slug = slugify(source)
if slug: # not all strings result in a slug value
instance.slug = slug
return model
return decorator
This registers a signal handler for specific models only, and lets you vary the source field with each model decorated:
#autoslug("name")
class NamedModel(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField()
#autoslug("title")
class TitledModel(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
Note that no attempt is made to generate a unique slug value. That would require checking for integrity exceptions in a transaction or using a randomised value in the slug from a large enough pool as to make collisions unlikely. Integrity exception checking can only be done in the save() method, not in signal hooks.
Receiver functions must be like this:
def my_callback(sender, **kwargs):
print("Request finished!")
Notice that the function takes a sender argument, along with wildcard keyword arguments (**kwargs); all signal handlers must take these arguments.
All signals send keyword arguments, and may change those keyword arguments at any time.
Reference here.

Categories