I have to retrieve M objects from a list of Q objects and then maps the M objects to an User. To achieve this, I need to run the code inside a transaction and roll back the DB in the case 1 of M objects are not created:
def polls(request, template_name='polls/polls.html'):
question_list = random.sample(list(Question.objects.all()), 3)
try:
with transaction.atomic():
for question in question_list:
UserToQuestion.objects.create(
user=request.user.id,
question=question.id
)
except IntegrityError:
handle_exception()
How I can achieve this? How the exception should be handled? The django documentation doesn't show a real example.
Is also possible perform this task during the user registration overriding the save method in way each registered user is mapped to N questions?
You need to use django signals while doing user registration.
Also you do not need with transaction.atomic(): part. You need to use
bulk create
First of all, we create a signal, in order to map the related questions to an user when the user is registered. The signal is triggered from post_save() and the call-back function retrieve N random questions and map it to the user. The signal must be connected, to do it, we use the decorator #receiver. We also need to use a transaction, cause of bulk_create() method.
signals.py
import random
from django.dispatch import receiver
from django.contrib.auth.models import User
from django.db import transaction
from django.db.models.signals import post_save
from polls.models import Question, UserToQuestion
#transaction.atomic
#receiver(post_save, sender=User)
def sig_user_registered(instance, **kwargs):
question_list = random.sample(list(Question.objects.all()), 3)
UserToQuestion.objects.bulk_create([
UserToQuestion(user=instance, question=question) for question in question_list
])
The signal must be imported. To do it, we use the method ready().
apps.py
from django.apps import AppConfig
class AccountConfig(AppConfig):
name = 'account'
def ready(self):
import account.signals
Finally, we load the application
settings.py
INSTALLED_APPS = [
# Django apps
# ...
# Third-party apps
# ...
# Your apps
'account.apps.AccountConfig',
# ...
]
Related
i want to use django signals to identify if a user is logged-in twice and if so, revoke his first session so that only one user session can be present at once.
i used the following example but it seems that my signals.py does not even gets reconcnized and i dont know why.
Example:
How to prevent multiple login in Django
accounts/signals.py
from django.contrib.auth import user_logged_in
from django.dispatch.dispatcher import receiver
from django.contrib.sessions.models import Session
from .models import UserSession
#receiver(user_logged_in)
def remove_other_sessions(sender, user, request, **kwargs):
# remove other sessions
Session.objects.filter(usersession__user=user).delete()
# save current session
request.session.save()
# create a link from the user to the current session (for later removal)
UserSession.objects.get_or_create(
user=user,
session=Session.objects.get(pk=request.session.session_key)
)
accounts/models.py
# Model to store the list of logged in users
class UserSession(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
session = models.OneToOneField(Session, on_delete=models.CASCADE)
accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'Accounts'
def ready(self):
import Accounts.signals
but for some reason nothing gets written onto the database for that table.
do i maybe miss something here, this is the very first time i get in touch with signals so i might missed something at the configuration.
Try this,
default_app_config = 'Accounts.apps.AccountsConfig'
Add this line in __init__.py file of your apps.py file directory.
I have a problem with duplicate signals. I have looked-up the relevant part of Django docs and a similar question on Stackoverflow but I still can't get it working right - i.e. the action that I have planned (creation on an ActivityLog entry) is actually happening 4 times :/
I have added the dispatch_uid and the problem still persists, so I guess I'm doing something wrong. Can you please hint me to the error?
Here's my code:
signals.py
from patient.models import Patient
from .models import ActivityLog
#receiver(pre_save, sender=Patient)
def create_new_patient(sender, instance, **kwargs):
ActivityLog.objects.create(
user=instance.created_by_user,
event='created a new patient',
patient_id=instance.patient_id
)
and this is it's usage in the patient.apps module:
from django.apps import AppConfig
from django.db.models.signals import pre_save
app_name = "patient"
class PatientConfig(AppConfig):
name = 'patient'
verbose_name = "Patients"
def ready(self):
from activity_logger.signals import create_new_patient
print('Patient APP is ready!')
pre_save.connect(create_new_patient, sender='patient.Patient', dispatch_uid='patient')
The print Patient APP is ready! does appear twice, and the object gets created 4 times, despite setting the dispatch_uid. What have I misunderstood?
The #receiver(Signal,...) decorator is a shortcut for Signal.connect(...), so you indeed register your create_new_patient handler twice (once thru #receiver when importing your signals module, the second time with pre_save.connect().
Solution : in your App.ready() method, you should just import your app's signal.py module. This will trigger the registration of the handlers decorated with #receiver.
I have a model.that I need to if any model with specific field created in database.send a Email to user for notify.I did some search too many apps are there for handling the notify. thats not my concern .I dont know how deploy this structure.any guide or example for this.for example :
if x = book.objects.create(title="book1") :
print("the book created")
if this action happend do something.
If you need to monitor object creation globally the best thing to use is signals
Like so:
from .models import Book
from django.db.models.signals import post_save
def book_created(sender, instance, created, **kwargs):
if created and instance.title == 'book1':
#logic here
post_save.connect(save_profile, sender=Book)
you need to stick that post_save.connect() function somewhere where it will be evaluated when the app is run, you can use app_dir/app.py for instance.
I have a django app that uses django-authopenid as the sole registration method. I have registration in my installed apps, which django-authopenid uses. An ideal solution would allow me to run arbitrary code on the user object when they register. I can't directly modify the code for django-authopenis or registration.
Let me know if I need to add any more details.
On models.py you could bind the post_save signal:
from django.contrib.auth.models import User, Group
from django.db.models.signals import post_save
def default_group(sender, instance, created, **kwargs):
if created:
instance.groups.add(Group.objects.get(name='your default group name'))
post_save.connect(default_group, sender=User)
If in doubt, read the signals documentation.
In my app I want to keep a track of all the questions that are being deleted. And so I have created a class(table) as such in my models file.
class Deleted(models.Model):
question = models.IntegerField(null=True, blank=True)#id of question being deleted
user = models.IntegerField(null=True, blank=True)#id of user deleting the question
dt = models.DateTimeField(null=True, blank=True)#time question is deleted
When a user tries to delete a question This delete function is called:
def delete_questions(request, user, questions):
for q in questions:
q.delete()
My doubt is how can i make a pre_delete signal of django to populate the new table I have created.
~newbie trying hefty task~
Thanks in advance:)
You start off by defining the receiver you want to use:
def log_deleted_question(sender, instance, using, **kwargs):
d = Deleted()
d.question = instance.id
d.dt = datetime.datetime.now() # consider using auto_now=True in your Deleted definition
# not sure how you'd get the user via a signal,
# since it can happen from a number of places (like the command line)
d.save()
Then define your receiver decorator:
from django.db.models.signals import pre_delete
from django.dispatch import receiver
#receiver(pre_delete, sender=Question, dispatch_uid='question_delete_log')
Add it altogether:
from django.db.models.signals import pre_delete
from django.dispatch import receiver
#receiver(pre_delete, sender=Question, dispatch_uid='question_delete_signal')
def log_deleted_question(sender, instance, using, **kwargs):
d = Deleted()
d.question = instance.id
d.dt = datetime.datetime.now()
d.save()
You can put this function in your models.py file, as you know it'll be loaded and connected up correctly.
The problem though, is that you don't get the user requesting the delete. Since a delete can be triggered from the django api (command line, shell, etc), which doesn't have a request associated with it. For this reason, you might want to avoid using signals if it's absolutely critical that you store the user along with the delete.