Django: to loop field while creating another instance - django

if i want to create another instance it doesnt pick the initial value.
this is my model.py
class Transaction(models.Model):
student= models.ForeignKey(Student,blank=True,null=True, on_delete=models.CASCADE)
schoollevy= models.ForeignKey(Schoollevy,blank=True,null=True, on_delete=models.CASCADE)
inputt=models.IntegerField(blank=True,null=True)
credit=models.IntegerField(blank=True,null=True)
debit=models.IntegerField(blank=True,null=True)
bal=models.IntegerField(blank=True,null=True)
descrip=models.CharField(max_length=200, blank=True,null=True)
date=models.DateField(auto_now_add=True, null=True, blank=True)
def save(self):
if self.schoollevy=="school fee":
self.debit += self.inputt
self.bal= self.credit-self.debit
return super(Transaction, self).save()
if i want to create a another instance it doesnt pick the first instance value

Related

How to override "Cannot asign must be an instance" in 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)

Checking if a field in model is modified and creating instance of another model

I have two models
Project Model
class Project(models.Model):
name = models.CharField(max_length=200)
workflow = models.ForeignKey("WorkflowType", null=True, blank=True, on_delete=models.SET_NULL)
created_on = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
def __str__(self):
return self.name
Workflow Instance Model
class WorkflowInstance(models.Model):
workflow_step = models.ForeignKey('WorkflowStep', null=True, blank=True, on_delete=models.CASCADE)
project = models.ForeignKey('Project', null=True, blank=True, on_delete=models.SET_NULL)
I want to check if the value of workflow field in "Project" models is added or changed for a particular project.
I am approaching the problem in following manner:
Checking if the previous and the new value of the "workflow" field in a project are different. If yes (modifies), then create the new instance of a project.
#receiver(pre_save, sender=Project)
def projectToBeUpdated(sender, instance, **kwargs):
if instance.id is None:
pass
else:
previous = Project.objects.get(id=instance.id)
if previous.workflow != instance.workflow:
print("workflow value modified. Please create a WorkflowInstance")
Problem: The comparison for previous and new value of the "workflow" field are happening in "pre_save" signal. But my new instance creation for workflowInstance is to be created in "post_save" signal. How can I do this?
Also, ideally I would like to store the previous value of workflow field in "pre_save" and get the new value of the field in "post_save". Reason being, save() method might fail for any reason, while I am comparing the previous and new value in "pre_save" method itself. Making changes in the database without confirming if the save() method executed successfully would be a wrong approach in my view.
You can override the model save method itself and use the following code logic, additionally if you want to identify what fields got modified you can use the dirtyfields package as well.
def save(self, *args, **kwargs):
if not self._state.adding:
changed_attr = self.get_dirty_fields()
else:
is_new = True
super().save(*args, **kwargs)```

Is there a way to pass the value of a model field as a parameter to models.ImageField(storage=function) within same Model

class StorageModel(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="profile", null=False)
file_meta = models.ImageField(storage=UserDataStorage(profile=user), blank=False, null=False)
class UserDataStorage(S3Boto3Storage):
location = common.AWS_LOCATION_TEST
file_overwrite = False
def __init__(self, *args, **kwargs):
for k, v in kwargs.items():
print("omg")
print(v)
super(UserDataStorage, self).__init__(*args, **kwargs)
How to pass the field user as an argument to the object UserDataStorage?
The problem here is, field user gets passed down to UserDataStorage but as a type <django.db.models.fields.related.ForeignKey>. I want a Profile instance here.
Is this achieveable in Django?
It's not possible the way you describe it. At this moment (when the code is initialized) the is no request/user objects to send.
What you can do is to pass a callable to the upload_to kwarg as explained in the docs.
This way when the callable is executed, you will have the model instance being saved, and this instance have the user attribute.
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class StorageModel(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="profile", null=False)
file_meta = models.ImageField(
upload_to=user_directory_path,
storage=UserDataStorage(),
blank=False, null=False
)

Django - Symmetrical relation OneToOneField

I'm writing and app to manage my network equipments. I created a model, RJ45port, which I can add to my equipment as needed. A RJ45port can be plugged into an other RJ45port and only one.
Here is the model I created :
class RJ45port(models.Model):
plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)
When I "plug" a RJ45port into another, I want the second one to have "plugged_into" set to the first one. I want the relation to be symmetrical. If I "unplug", I want both of the RJ45 ports to have "plugged_into" set to null, or blank.
I found a bit of code, it might be a hint :
def save(self, *args, **kwargs):
super(RJ45port, self).save()
self.plugged_into.plugged_into = self
To be honest I'm a bit lost here and it's the final step I need to get this app functional...
You are best suited just making a model plug_into() method, and then using it to "plug" one instance into another, as well as an unplug() method.
Example:
class RJ45port(models.Model):
plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)
def plug_into(self, instance):
self.plugged_into = instance
instance.plugged_into = self
self.save(update_fields=['plugged_into'])
instance.save(update_fields=['plugged_into'])
return [self.plugged_into, instance.plugged_into]
def unplug(self):
self.plugged_into.plugged_into = None
self.plugged_into = None
self.plugged_into.save(update_fields=['plugged_into'])
self.save(update_fields=['plugged_into'])
return [self.plugged_into, instance.plugged_into]
And then you can call it like this:
port_1 = Port.objects.all()[0] # First port
port_2 = Port.objects.all()[1] # Second port
port_1.plug_into(port_2) # Should return [instance, instance]
port_1.unplug() # Should return [None, None]
You are right. Simply override the save method. But call super().save() at the end:
class RJ45port(models.Model):
plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)
def save(self, *args, **kwargs):
self.plugged_into.plugged_into = self
super(RJ45port, self).save()
Another option is to use a related_name so you can make a reverse access from the referenced instance, so you can say that the relationship becomes "symetrical". The only downside is that you can't use the same name to reference both connections:
class RJ45port(models.Model):
plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True, related_name='plugged_from')
In this example, plugged_from can be queried like any other field from the referenced instance.

Django Rest : Model field default value only while creating

I have a model with 2 char-fields. I want to give them default values when a row is getting created. This default values are sort of IDs which depends on time. This ID should never change. i.e. the default value should not be applied when subsequent updates happen on the row.
I'm trying to use update_or_create but, the defaults while creating & updating are not same. How can I put these Ids only while creating and ignore while updating?
I'm referring to this answer but no luck.
EDIT:
Following is the code for reference:
Model:
class UsersModel(models.Model):
id = models.CharField(db_column="id", max_length=25, primary_key=True)
key = models.CharField(db_column="key", max_length=100)
a = models.CharField(db_column="a",max_length=25, null=True, blank=True)
b = models.BigIntegerField(db_column="b", null=True, blank=True)
Views:
def post(self, request, format=None):
UsersModel.objects.update_or_create(a="a_val",defaults={"b":"b_val"})
Here, I want the id & key to take default values when the row is being created. When it is being updated, only b should get updated as shown in above code.
The same can be achieved by overiding the save function of models.Model to ensure that an id and key is given a value(default) in your case if the model is being created.
class UsersModel(models.Model):
id = models.CharField(db_column="id", max_length=25, primary_key=True)
key = models.CharField(db_column="key", max_length=100)
a = models.CharField(db_column="a",max_length=25, null=True, blank=True)
b = models.BigIntegerField(db_column="b", null=True, blank=True)
def save():
if not self.id:
self.id=get_default('id')
if not self.key:
self.key=get_default('key')
super(UsersModel, self).save(*args, **kwargs)
This will ensure when you create and update, the first time save is called, these variables are assigned a default value before getting saved in the db.