I'm trying to assign a group to every new user registered into the system. I've already read something about it in another questions but I don't really know where to add the necessary code to make it work.
I'm using Django 2.1.3 and I'm logging users using allauth (social login, but it shouldn't make any difference as a new instance in the User table is created)
You can use a #post_save signal for example that, each time a User is created, adds the given group to the groups of the User. Typically signals reside in a file named handlers.py in the signals directory of an app, so you probably should create or modify the files listed in boldface:
app/
signals/
__init__.py
handlers.py
__init__.py
apps.py
...
# app/signals/handlers.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from django.contrib.auth.models import Group
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def save_profile(sender, instance, created, **kwargs):
if created:
g1 = Group.objects.get(name='group_name')
instance.groups.add(g1)
where group_name is the name of the group you want to add.
You should then import the handlers.py module in your MyAppConfig (create one if you do not have constructed such config yet):
# app/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'app'
verbose_name = "My app"
def ready(self):
import app.signals.handlers
and register the MyAppConfig in the __init__.py of the app:
# app/__init__.py
default_app_config = 'app.apps.MyAppConfig'
If this should happen for any new User instance, you can connect a handler to the post_save signal:
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def handle_new_job(sender, **kwargs):
if kwargs.get('created', False):
user = kwargs.get('instance')
g = Group.objects.get(name='whatever')
user.groups.add(g)
Include this code in your app and make sure it is imported as stated e.g. here.
Related
I want to initialize the database table with some predefined instances.
# apps.py
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def initialize(sender, **kwargs):
from .models import Address
Address.objects.create(
# address fields
)
print('Created')
class BackendConfig(AppConfig):
name = 'backend'
def ready(self):
print('Ready')
post_migrate.connect(initialize, sender=self)
However nothing was created and nothing was printed after migration like the signal not triggered at all.
Sorry I am dumbass.
Need to mention default_app_config = 'backend.apps.BackendConfig' in __init__.py
I made this before with django like this:
signals/handlers.py
from django.dispatch import receiver
from django.conf import settings
from django.contrib.auth.models import Group
from users.models import *
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def save_profile(sender, instance, created, **kwargs):
if created:
g1 = Group.objects.get(name='Editors')
instance.groups.add(g1)
apps.py
from django.apps import AppConfig
class RegistrationConfig(AppConfig):
name = 'registration'
def ready(self):
import registration.signals.handlers
but I don't know how to make it with wagtail !
thanks.
Instead of using Django signals, Wagtail has hooks that simplify this for you. You can also send password reset email etc... after creating user using the same technique.
Just create a wagtail_hooks.py in your app:
from django.contrib.auth.models import Group
from wagtail.core import hooks
#hooks.register('after_create_user')
def add_user_to_group(request, user):
if user:
group, created = Group.objects.get_or_create(name='Group Name')
user.groups.add(group)
Docs: https://docs.wagtail.io/en/latest/reference/hooks.html?highlight=after_create_user#id40
I read a part of the doc, and some articles, but my code is not working.
OBS: i'm using custom User created with AbstractUser, but i not add extra fields
Look this example
profile.signals.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
from .models import Profile
User = get_user_model()
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
now, look in the user creation:
>>> from accounts.models import User
>>> me = User.objects.create(username='myusr', email='me#email.com', password='me123456')
>>> me
<User: myusr>
>>> me.save()
>>> me.profile
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/mnt/sda4/Development/coding/Projects/codesv3/env/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 415, in__get__
self.related.get_accessor_name()
accounts.models.User.profile.RelatedObjectDoesNotExist: User has no profile.
i dont know what's wrong. Also because I have not used it before and i not know about SQL triggers
In your signals.py file, save profile after it's created, like below:
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
Make sure, you import signals in your related apps.py file like below example:
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
Then also make sure you have made the below change:
you must add app's config to either of two files.
In your settings.py file's INSTALLED_APPS, like mentioned in this link: Django create profile for user signal.
OR,
In your related app's __init__.py file, like this (in this example, the related app is users): default_app_config = 'users.apps.UsersConfig'
First, this command create user and you do not need to save it after creating:
me = User.objects.create(username='myusr', email='me#email.com', password='me123456')
Second, where your signals places? If you put it in models everything should works.
Also you can place where you want but you need to import it in your apps like here:
class ProfileConfig(BaseConfig):
name = ...
def ready():
import profiles.signals # where your signals place
I am trying to add a user to a group when the user is created. I have seen a few different ways to accomplish similar things with signals but nothing I am trying has seemed to work.
In the shell, I ran Group.objects.get(name='User') to make sure that the group was being recognized.
signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
#receiver(post_save, sender=User)
def add_user_to_user_group(sender, instance, created, **kwargs):
try:
if created:
instance.groups.add(Group.objects.get(name='User'))
except Group.DoesNotExist:
pass
This part I am very unsure of, I have seen a few different ways people have done this part. One tutorial did it this way but I am not sure what just importing the signals would do
app.py
from django.apps import AppConfig
class UserConfig(AppConfig):
name = 'User'
def ready(self):
import User.signals
I'm trying to setup a signal so that when a valid form is saved, a function is ran to carry out a related task.
My app structure is as follows;
- events
- helpers
- __init__.py
- status.py
- models
- signals
- __init__.py
- event.py
- __init__.py
- event.py
- status.py
- views
- __init__.py
- event.py
I believe signals need to be imported as early as possible, before models, so at the top of models/__init__.py I've got from .signals import *.
# views/event.py
class AddEventView(CreateView):
"""
View for adding an Event.
"""
model = Event
form_class = EventForm
success_url = reverse_lazy('events:all_events')
def form_valid(self, form):
self.object = form.save()
signals.event_status.send(
sender=None, request=self.request, event=self.object, status=None
) # Should the sender be self.object?
return super(AddEventView, self).form_valid(form)
# signals/event.py
from django.dispatch import Signal
event_status = Signal(providing_args=["request", "event", "status"])
# helpers/status.py
from ..models import Status, StatusHistory
from ..models.signals import event_status
def create_status(sender, **kwargs):
"""
Create a status for a given event.
"""
event = kwargs['event']
status = kwargs['status']
creator = User.objects.get(pk=event.creator)
try:
current_status = StatusHistory.objects.filter(
event=event).order_by('timestamp')[0]
except IndexError:
# Not sure what we're doing here yet.
pass
if not status:
status = Status.objects.get(description=_("Submitted"))
statushistory = StatusHistory.create(
event=event,
event_status=status,
user=creator
)
statushistory.save()
event_status.connect(create_status)
I'm running the debug server in Pycharm with a break point in the create_status() function & it's never getting hit.
Have I implemented this wrong?
I've used signals in some of my projects and I allways import the signals in the __init__.py of my Django APP (Same folder as settings.py, views.py, urls.py...)
__init__.py:
import signals
signals.py:
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from my_project.models import *
#receiver(post_save, sender=Modelname) # Called after an object is saved
def create_modelname(sender, **kwargs):
obj = kwargs['instance'] # I get the object being saved here
# ... Here I do whatever I want
#receiver(pre_delete, sender=Modelname) # Called before an object is deleted
def delete_modelname(sender, **kwargs):
obj = kwargs['instance']
# ... Do whatever you need
Remember this 2 imports:
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
Remember to import the signals
To import the signals you need to add import signals in your __init__.py of your project
Using this code, this functions are called automatically by Django when an object of the class Modelname is created or deleted.
The receiver for created object is called after the object is created, and the receiver for deleted object is called before the object is deleted.
I think maybe you just need to import your helpers/status.py eg in models/__init__.py
otherwise your event_status signal gets defined ok but the signal handler create_status never gets connected by Django
if you only have one handler for that signal it might make sense to put it in the same module as the signal definition
I found one case that signal is not working.
Here are cases that signal(pre_save, post_save) won't happen.
Model.objects.filter(pk=pk).update(key=value)
Bulk model functions won't happen signals.