How to override "Cannot asign must be an instance" in Django? - django

I have two models:
class Message(models.Model):
username = models.CharField(max_length=255)
room = models.CharField(max_length=255)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Notification(models.Model):
notification_author = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="notifauthor")
notification_from = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="notiffrom")
is_read = models.BooleanField(default=False)
signals:
#receiver(post_save, sender=Message)
def create_user_notification(sender, instance, created, **kwargs):
if created:
Notification.objects.create(
notification_author=instance.username,
notification_from=instance.room)
#receiver(post_save, sender=Message)
def save_user_notification(sender, instance, **kwargs):
instance.username.save()
I am trying to create signal for creating notification after message is created. But have error:
Cannot assign "20": "Notification.notification_author" must be a "Profile" instance.
How to override it (if possible) without changing CharField to FK in Message model?
Found smth about eval(), but it does not still work

The question is how to convert the string to Profile model without
using FK
notification_author=Profile.objects.get_or_create(username=instance.username)

Related

django model override save m2m field

I want to update m2m field on save() method
I have the following model:
class Tag(models.Model):
label = models.CharField(max_length=50)
parents_direct = models.ManyToManyField("Tag", related_name="children", blank=True)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(null=True, blank=True)
administrators = models.ManyToManyField(
to=KittyUser, related_name="administrated_tags", blank=True)
moderators = models.ManyToManyField(
to=KittyUser, related_name="moderated_tags", blank=True)
allowed_users = models.ManyToManyField(
to=KittyUser, related_name="allowed_tags", blank=True)
visible = models.BooleanField(default=True, verbose_name="visible to anyone")
POSTABILITY_CHOICES = (
('0', 'any allowed user can post'),
('1', 'only moderators\\admins can post')
)
postability_type = models.CharField(default='0',
max_length=1,
choices=POSTABILITY_CHOICES)
parents_tree = models.ManyToManyField("Tag", related_name="parents_tree_in_for", blank=True)
related_tags = models.ManyToManyField("Tag", related_name="related_tags_in_for", blank=True)
def save(self, *args, **kwargs):
self.label="overriden label"
super(Tag, self).save(*args, **kwargs)
self.parents_tree.add(*self.parents_direct.all())
breakpoint()
super(Tag, self).save(*args, **kwargs)
Through django-admin the tags get created, the label substitution works, though parents_tree don't get updated.
If I create it from the shell, it is swearing at the second super().save:
django.db.utils.IntegrityError: duplicate key value violates unique constraint "posts_tag_pkey"
If you take away the first super.save(), you get the following:
"<Tag: overriden label>" needs to have a value for field "id" before this many-to-many relationship can be used.
in both shell and admin.
The question is, how to update my m2m field on save?
Another question is why does it work differently in admin panel and shell?
As a temporary solution I managed to listen to the signal of updating parents_direct field, but what if I wanted to depend on non-m2m fields?
from django.db.models.signals import m2m_changed
def tag_set_parents_tree(sender, **kwargs):
if kwargs['action'] == 'post_add' or 'post_remove':
parents_direct = kwargs['instance'].parents_direct.all()
if parents_direct:
kwargs['instance'].parents_tree.set(parents_direct)
for tag in parents_direct:
kwargs['instance'].parents_tree.add(*tag.parents_tree.all())
else:
kwargs['instance'].parents_tree.clear()
m2m_changed.connect(tag_set_parents_tree, sender=Tag.parents_direct.through)

Foreign key in django signals

i need use node in created method signals, but raise this error
my signals :
#receiver(post_save, sender=AUTH_USER_MODEL)
def create_user_progress(sender, instance, created, **kwargs):
specialties = instance.specialties
section = SectionSpecialties.objects.filter(specialties=specialties)
section_slice = section.values_list('section_id', flat=True)
node = Nodes.objects.filter(sections__in=section_slice)
if created:
Progress.objects.create(user=instance, node=node)
my error :
Cannot assign "<QuerySet [<Nodes: dsdsd - cccc>, <Nodes: chizi nemiyare - cccc>]>": "Progress.node" must be a "Nodes" instance.
my model :
class Progress(core_models.TimeStampedModel):
node = models.ForeignKey(section_model.Nodes, related_name='mentor_user', on_delete=models.CASCADE, null=True)
mentor = models.ForeignKey(mentor_user.MentorUser, related_name='mentor_user', on_delete=models.CASCADE, null=True)
user = models.OneToOneField(User, related_name='mentor_user', on_delete=models.CASCADE)

How to write activity history in Django, when we have more than one ManyToMany fields in the model?

We are using 'actstream' library and its not updating the actual many2many field id values into history table. Always its updating as an empty list instead of list of ids.
class Parent():
name = models.CharField(max_length=255)
tags = TaggableManager(blank=True)
def __str__(self):
return self.name
class Table1():
name = models.CharField(max_length=255, null=True)
type = models.CharField(max_length=255, null=True)
parent_id = models.ManyToManyField(ParentTable, blank=True, related_name='%(class)s_parent_id')
tags = TaggableManager(blank=True)
def __str__(self):
return self.name
'id' is auto incremented value in Django table. Once we call a save() method, then post_save signal will execute for logging additional information in the actstream table.tags and parent_id is updating as [] instead of user sending values in the actstream_action table.we are using #receiver(post_save) annotation and executing action.send() accordingly
#receiver(post_save)
def capture_models_post_save(sender, instance, created, **kwargs):
userInfo = get_current_user()
action.send(userInfo, verb='created',description='created',action_object=instance, modification=model_to_dict(instance))

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()

Post_save signal implementation in Django

I have models like this:
class Devices(models.Model):
name = models.CharField(max_length=255, blank=True)
uniqueid = models.CharField(db_column='uniqueid'.lower(), max_length=255, blank=True) # Field name made lowercase.
latestposition = models.ForeignKey('Positions', db_column='latestPosition_id'.lower(), blank=True, null=True) # Field name made lowercase.
class Meta:
db_table = 'devices'
verbose_name = 'Devices'
verbose_name_plural = verbose_name
def __unicode__(self):
return '%s' %(self.name)
# Call the signal to create user device when the device is created.
dispatcher.connect(save_user_device, signal=post_save, sender=Devices)
class UsersDevices(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
devices = models.ForeignKey('Devices')
class Meta:
db_table = 'users_devices'
verbose_name = 'User Devices'
verbose_name_plural = verbose_name
def __unicode__(self):
return '%s %s' %(self.user, self.devices)
When the Devices is created, I want to create users devices. user field in the UsersDevices would be signed in user who created device and devices would be the device that was just created.
def save_user_device(sender, instance, **kwargs):
## Problem is here
instance.UsersDevices.create( )
How can I create a UsersDevices using this signal with the user instance and device instance
You don't really need signals in this case. Overwrite the save() method of the model:
def save(self, *args, **kwargs):
# Call the original save function to actually save the model:
super(Devices, self).save(*args, **kwargs)
# Now this model is saved, so we can create the UsersDevices
UserDevices(user=get_user_from_somewhere(), devices=self).save()
See the documentation for more information about overwriting the save() method:
https://docs.djangoproject.com/en/1.7/topics/db/models/#overriding-model-methods
It is better to redefine save method of Devices model for this purpose. But if you want to use signals it might be done like this:
def save_user_device(sender, instance, **kwargs):
## Problem is here
UsersDevices.create(devices=instance, user=instance.user)
In this case you have to add 'user' field to Devices model.
And small tip: you should give names to models singularly, plural names is bad style.