Changing model field within the Django Shell - python

Is there anyway to use the Django shell to modify a field value? I can create, delete, and query models, but I don't know how to alter existing field values.
class Game(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Game, self).save(*args, **kwargs)
def __str__(self):
return self.name
In the Django shell, I try Game.objects.get(name="testb").likes = 5, but it still outputs likes = 0 when I input Game.objects.get(name="testb").likes right afterwards.

You should save the changes,
game = Game.objects.get(name="testb")
game.likes = 5
game.save()

Calling Game.objects.get() retrieves the data from the database.
When you execute the statement Game.objects.get(name='test').likes = 5, you are retrieving the data from the database, creating a python object, and then setting a field on that object in memory.
Then, when you run Game.objects.get(name='test') again, you are re-pulling the data from the database and loading a python object into memory. Note that above, when you set likes to 5, you did that purely in memory and never saved the data to the database. This is why when you re-pull the data, likes is 0.
If you want the data to be persisted, you have to call game.save() after setting the likes field. This will enter the data into the database, so that the next time you retrieve it via .get(), your changes will have persisted.

If u need change all fields for all items, just try this:
from shop.models import Product
Product.objects.filter(recommend=True).update(recommend=False)
U can use this in Django Shell. Have a nice time :)

Related

Clone model object values Django

i want to clone the values from existing model object and sanitize the values for special characters to provide a better search. So i already have values in the database that i want to sanitize and store in a new object after.
This is a code example:
class Entry(models.Model):
headline = models.CharField(max_length=255)
sanitized_headline = models.CharField(max_length=255)
I would like populate all the sanitized_headline objects with the corresponding headline values after some character replacements like this re.sub('č', 'c', headline) applied to headline before cloning, as well as do this for every new entry.
Im using Django for a GraphQl API character replacement can't be done through a view.
Thank you
To sanitize the existing objects: [provided that you have a function to sanitize the text called sanitize]
Enter your Django shell (using python manage.py shell) and import Entry model. Then:
all_entries = Entry.objects.all()
for obj in all_entries:
obj.sanitized_headline = sanitize(obj.headline)
obj.save()
To automatically sanitize new objects, you have to override the save method:
class Entry(models.Model):
headline = models.CharField(max_length=255)
sanitized_headline = models.CharField(max_length=255)
def save(self, *args, **kwargs):
self.sanitized_headline = sanitize(self.headline)
super().save(*args, **kwargs)

Django many to many relation not saving

Update:
For anyone curious, I figured out what and why and how to fix it.
In my view I had:
fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image']
And am using {{ form.as_p }} in my template. Apparently once that gets posted from the form it really, really doesn't want anything else touching the form fields that wasn't already in the form.
So I took out the 'tags' field from my view and it works.
Thanks to everyone that responded.
Original Question:
Using Django 2.0.1 and PostgreSQL 9.2.18
I'm writing a simple photogallery application. In it I have a photo object and PhotoTag object. The photo can have many tags and the tags can be associated with many photos, thus it needing to be a ManyToManyField.
Upon save of the submitted photo, a post_save receiver calls functions to make thumbnails (which work fine) and a function to update tags.
The photo gets saved fine, update_tags gets called fine, tags get read from the photo fine, tags get saved into PhotoTag fine. But the manytomany table tying the two together does not get the new rows inserted. Unless the code exits abnormally during either the update_tags function or the post_save receiver function, thumbs after update_tags is called.
I've even tried using a connection.cursor to write directly into the m2m table and it has the same behavior.
If I try to call save() on the Photo object again, I just get into an infinite loop due to the post_save signal.
I'm baffled as to what is going on. Any clues?
# models.py
def update_tags(instance):
tags = get_tags(instance.image)
# Set initial values
pt = []
tagid = ''
photoid = instance.id
# Loop through tag list and insert into PhotoTag and m2m relation
for x in range(0, len(tags)):
# Make sure this tag doesn't already exist
if PhotoTag.objects.filter(tag_text=tags[x]).count() == 0:
pt = PhotoTag.objects.create(tag_text=tags[x])
tagid = PhotoTag.objects.latest('id').id
instance.tags.add(pt)
else:
# Only working with new tags right now
pass
return
class Photo(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
title = models.CharField(max_length=200, null=True, blank=True)
text = models.TextField(null=True, blank=True)
html = models.BooleanField(default=False)
filename = models.CharField(default='', max_length=100, blank=True,
null=True)
image = models.ImageField(upload_to=upload_path)
location = models.CharField(max_length=100, blank=True, null=True)
entry_date = models.DateTimeField(default=timezone.now)
taken_date = models.DateTimeField(blank=True, null=True)
tags = models.ManyToManyField(PhotoTag, blank=True)
#receiver(post_save, sender=Photo)
def thumbs(sender, instance, **kwargs):
"""
Upon photo save, create thumbnails and then
update PhotoTag and m2m with any Exif/XMP tags
in the photo.
"""
mk_thumb(instance.image, 'mid')
mk_thumb(instance.image, 'th')
mk_thumb(instance.image, 'sm')
update_tags(instance)
return
-------------
From views.py
-------------
class PhotoCreate(LoginRequiredMixin, CreateView):
model = Photo
template_name = 'photogallery/photo_edit.html'
fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image']
def get_initial(self):
self.initial = {'entry_date': timezone.now()}
return self.initial
def form_valid(self, form):
form.instance.author = self.request.user
return super(PhotoCreate, self).form_valid(form)
Update:
def save(self, mkthumb='', *args, **kwargs):
super(Photo, self).save(*args, **kwargs)
if mkthumb != "thumbs":
self.mk_thumb(self.image, 'mid')
self.mk_thumb(self.image, 'th')
self.mk_thumb(self.image, 'sm')
self.update_tags()
mkthumb = "thumbs"
return
I had a similar issue where I was trying to add a group when a user instance was saved.
The anwer why this is happening is at the docs and more explicitly (using code) at this ticket.
When saving a ModelForm() (hitting save in the admin), first an instance of the object is saved, then all its signals are triggered etc. The third step is to save all m2m relations using ModelForm().cleaned_data. If ModelForm().cleaned_data['tags'] is None, all the relations created from your signal, will be deleted.
A hackish solution, is to use a post_save signal with transaction.on_commit() which will execute the relevant code after the existing transaction (which includes the procedure of saving all m2m relations) is committed to the database.
def on_transaction_commit(func):
''' Create the decorator '''
def inner(*args, **kwargs):
transaction.on_commit(lambda: func(*args, **kwargs))
return inner
#receiver(post_save, sender=Photo)
#on_transaction_commit
def tags(instance, raw, **kwargs):
"""
Create the relevant tags after the transaction
of instance is committed, unless the database is
populated with fixtures.
"""
if not raw:
update_tags(instance)
A more sound solution if your many to many relation has not blank=True is to use a m2m_changed() signal, as explained in this post or the before mentioned ticket.
The best of all, is to ditch the signals and override the ModelForm().clean() method for the case where a ModelForm() is used, and also override the Model().save() method in case the model is directly saved.
A ModelForm().instance.my_flag will be useful so you can check for an existing Model().my_flag in Model().save() to avoid accessing twice the database.
override your save method like
def save(self, *args, **kwargs):
tags = get_tags(self.image)
# Set initial values
pt = None
# Loop through tag list and insert into PhotoTag and m2m relation
for x in range(0, len(tags)):
# Make sure this tag doesn't already exist
if PhotoTag.objects.filter(tag_text=tags[x]).count() == 0:
pt = PhotoTag.objects.create(tag_text=tags[x])
self.tags.add(pt)
else:
# Only working with new tags right now
pass
super(Photo, self).save(*args, **kwargs)

Django model save override not changing self

I'm stuck using a non-Django legacy MySQL database. I need to write code that generates a unique filename each time a model object is saved. The following doesn't work. It won't overwrite the filename field. It saves fine with whatever the filename field was set to. Is this because that field is set as the primary key?
(I realize my code isn't creating a random filename--haven't gotten that far yet. Also, I know this will only save once since it needs to be unique, but it won't even save the first time).
class Agenda(models.Model):
type = models.IntegerField()
filename = models.CharField(max_length=45, primary_key=True)
date = models.DateField()
class Meta:
managed = False
db_table = 'gbminutes'
def save(self, *args, **kwargs):
self.filename = 'ATESTFILE'
super(Agenda, self).save(*args, **kwargs)

Django, defining extra model fields on db level instead of programming level

I am using Python 2.7 and Django 1.6.3
I want to define extra model field which is not actually in db table. I have a way which is defining a callable method with property annotation like;
class MyClass(models.Model):
my_field = models.CharField(max_length=50)
#property
def my_extra_field(self):
return self.my_field+'extra value'
This works fine to show it on admin change list pages. But the extra field is not on db level. It is being generated on programming level. Django asks it for every model object.
This cause me some troubles. My all admin change list pages have capability of exporting as excel or some other type. I am using admin query set to build that report. I have also jasper reports mechanism that works with SQL select queries. So, I, want to use the queryset to take this select query.
I think being able to define extra fields on db level is important for something. Not just for reason of mine. So, the question all about this.
Is there a way to define an extra custom fields on db level instead of programming level in Django.
Thank you!.
Edited
Adding it to admin list_filter is also another problem if it is not really a field. Django does not allow you to add it.
Could you create a new database field and then overwrite the save method to populate that field? I do that often to create a marked up version of a text field. For example:
class Dummmy(models.Model):
content = models.TextField()
content_html = models.TextField(editable=False, null=True)
def save(self, *args, **kwargs):
self.content_html = markdown(self.content)
super(Dummmy, self).save(*args, **kwargs)
So for you:
class MyClass(models.Model):
my_field = models.CharField(max_length=50)
my_extra_field = models.CharField(editable=False, null=True)
def save(self, *args, **kwargs):
self.my_extra_field = self.my_field + 'extra value'
super(MyClass, self).save(*args, **kwargs)

django multiple update dates in one field

What would be the best way to create a "Update history" field in my Django Model so that I can keep track of multiple update dates?
I can create a model with last_updated = models.DateTimeField() and then have my view save the datetime to it, but what if I want to have a history of when the user has updated their post, and not just the most recent save?
Should it be a ManyToManyField or a CharField instead?
It's shouldn't be a field at all. Instead create a model, that will reference your main model using a ForeignKey:
class YourModel(models.Model):
name = models.CharField(max_length=100)
class YourModelUpdateHistory(models.Model):
your_model = models.ForeignKey('YourModel')
updated = models.DateTimeField()
This way you can have multiple dates for every model, while keeping the database properly normalized. It will also allow you in the future to add additional fields with other information about each update (for example who updated the object).
You should create a new YourModelUpdateHistory object whenever you update a YourModel object. You can even set it up so this is done automatically, thanks to the save() method (which is called by Django every time you save an object):
from django.utils import timezone
class YourModel(models.Model):
name = models.CharField(max_length=100)
def save(self, *args, **kwargs):
super(YourModel, self).save(*args, **kwargs)
YourModelUpdateHistory.objects.create(your_model=self, updated=timezone.now())

Categories