Clone model object values Django - python

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)

Related

Django Models (dynamic?)

I am just starting Django Website;
I have deciced to go with a model (with SQLite DB), which have the following properties:
class Flow(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="Owner", default="ADMIN")
source = models.CharField(default='HTTP', choices=SOURCE_CHOICES, editable=True, max_length=12)
name = models.CharField(max_length=50, default=" ")
date = models.DateTimeField(verbose_name="Creation date")
I want to add others fields to this model depending on the source field value.
For example if the source field : 'File' is selected. I will create additionnal field (like file name, file directory ...) If 'Http' is selected, I will create a field URL.
Thus depending on the source field, I will have differents field and type.
I have read this kind of model is difficult to reprensent in Django; I am open minded to other kind of solution. My idea was to created as many model as the possible source value.
Even if you can create dynamic field in Django, you can't create dynamic column in Sqlite table FLOW.
If you plan to use same types of fields in different cases, you can create field with abstract name, for example path. That can be as URL as local file path.
In common way you need to create all columns for all choices for DB table.
class Flow(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="Owner", default="ADMIN")
source = models.CharField(default='HTTP', choices=SOURCE_CHOICES, editable=True, max_length=12)
name = models.CharField(max_length=50, default=" ")
date = models.DateTimeField(verbose_name="Creation date")
local_path = models.ImageField(upload_to='files', null=True, blank=True) # when source is file
url = models.URLField(null=True, blank=True) # when source is http
So local_path may be empty when you using HTTP source.
Inside view you can dynamically get (or set) value through serializer:
class FlowSerializer(serializers.ModelSerializer):
path = serializers.SerializerMethodField(method_name='get_path_value')
class Meta:
model = Flow
fields = ('owner', 'source', 'name', 'date', 'path')
def get_path_value(self, instance):
if instance.source == 'HTTP':
return instance.url
else:
return instance.local_path
So path will be different for different sources.
And maybe you will be need to install django rest framework for this solution.
EDIT1:
answering to question
So if I understand well, the best pratices should be to create 'blank'
columns
You definitely must to describe all columns in table (unless you using non Sql-like DB, such as MongoDB). So yes, create 'blank' columns, is only one possible way.
But you can override save method in model, for dynamically save fields:
class Flow(models.Model):
temp_path = None
path = models...
url = models...
choice = models...
def save(self, *args, **kwargs):
if choice == 'HTTP':
self.url = temp_path
else:
self.path = temp_path
super().save(*args, **kwargs)
Code above is just a quick idea. Not really working code.
You could implement a custom model field type for that, it helps you save a union object in one column in database. The raw type in database could be a JSON string or other serialized types, for the model field's usage, it's just a python native object!
Here is a piece of sample code: the main jobs are these two methods:
class HandField(models.Field):
# ...
def from_db_value(self, value, expression, connection):
if value is None:
return value
return parse_hand(value)
def to_python(self, value):
if isinstance(value, Hand):
return value
if value is None:
return value
return parse_hand(value)
Check the official docs for details.

Changing model field within the Django Shell

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

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

Code based unique constraint Django Model

I have a Django model that looks like this:
class Categories(models.Model):
"""
Model for storing the categories
"""
name = models.CharField(max_length=8)
keywords = models.TextField()
spamwords = models.TextField()
translations = models.TextField()
def save(self, force_insert=False, force_update=False):
"""
Custom save method that converts the name to uppercase
"""
self.name = self.name.upper()
super(Categories, self).save(force_insert, force_update)
Whenever the data is inserted or updated. I'd like to check that that a record with same name doesn't exists. It's a unique constraint that I'd like to implement via code and not the DB. The amount of data in this table is minuscule so the the performance hit is not an issue. If there is an constraint violation, I'd like to raise one of Django's inbuilt constraint exceptions instead of creating a custom one.
Could someone how me the best/fastest way to accomplish this?
Thanks.
In your model definition you can tell Django that 'name' should be unique:
name = models.CharField(max_length=8, unique=True)
A django.db.IntegrityError will be raised if you attempt to save two records with the same name.
in the view
try:
Category.objects.get(name='name')
except Category.DoesNotExist:
# call the save method of model

Categories