how to save one column value based on id column in django - python

I would like to save model id along with other format characters into another column, based on the model id being automatically created. For example,
For example, I have column name formated_id in shipment model, and want set its value to "easter" + ID which is automatically generated. How could I achieve that? Thanks.
class Shipment(models.Model):
formated_id = models.CharField("formatedid",max_length= 50)
class Meta:
ordering = ['-id']
def save(self, *args, **kwargs):
super().save(*args, **kwargs)

You would need to set the formated_id after the instance is first saved, which is when the primary key is created. Something along the lines of the following (untested) code should do the trick
class Shipment(models.Model):
formated_id = models.CharField("formatedid",max_length= 50)
class Meta:
ordering = ['-id']
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.formated_id = 'easter{}'.format(self.pk)
super().save(*args, **kwargs)

Related

how to autoupdate category by the amount of products in django model

I have a model of the category with title and count and I also have another model called Products which has category as one of its foreign-key. How can I auto-update the category count field by the number of products that comes under the same category?
class Category(models.Model):
title = models.CharField(max_length = 20)
count = models.IntegerFIeld()
class Product(models.Model):
title = models.CharField(max_length = 20)
category = models.ForeignKey(Category, on_delete = models.CASCADE)
You can either override save method or write a signal to auto-update the field, i.e.:
class Category(models.Model):
def save(self, *args, **kwargs):
self.count = self.product_set.count()
super().save(*args, **kwargs)
or with signals:
from django.dispatch import receiver
#receiver(post_save, sender=Category)
def category_post_save(sender, instance, *args, **kwargs):
instance.count = instance.product_set.count()
instance.save()
But I would suggest you using a calculated property:
class Category(models.Model):
...
#property
def count(self):
return self.product_set.count()
If you want to keep the field count I recommend you use signals. You should use post_signal and pre_signal (to get the previous category from a query) on the model Product.
Here are the signals:
#receiver(signals.pre_save, sender=Product)
def product_pre_save_signal(sender, instance, *args, **kwargs):
if instance.id:
previous_instance = Product.objects.get(id=instance.id)
if previous_instance.category != instance.category:
instance.previous_category = previous_instance.category
#receiver(signals.post_save, sender=Product)
def product_post_save_signal(sender, instance, created, *args, **kwargs):
if not created:
if hasattr(instance, "previous_category"):
if instance.previous_category:
instance.previous_category.count -= 1
instance.previous_category.save()
if instance.category:
instance.category.count += 1
instance.category.save()
else:
if instance.category:
instance.category.count += 1
instance.category.save()
Another recommendation for this situation is, make it a read-only field(add editable=False to the field declaration), so no one can edit it from Django admin or serializer.
But I highly recommend you remove the field because it's hard to keep this field sync with the table Product, so calculate the value each time.
You can have almost any query that is related field count over Category or Product, so don't worry:)

how to get ManyToMany field data in model save method

class Product(models.Model):
varient_property = models.ManyToManyField(to='store.AttributeValue', blank=True)
def save(self, *args, **kwargs):
super(Product, self).save(*args, **kwargs)
# here varient_propery is manytomany field
# here i am saving this from django admin panel
print(self.varient_property.all())
many to many class
class AttributeValue(models.Model):
value = models.CharField(max_length=30)
available = models.BooleanField(default=True)
def __str__(self):
return self.value
the print statement returns none
how can I get many to many data after my model gets save?
I want all set many-to-many relations.
thanks in advance.
You can try this:
If you want all the records from AttributeValue model you need to use the all() method on the class not on the instance that you obtain from varient_property in Product model.
class Product(models.Model):
varient_property = models.ManyToManyField(to='store.AttributeValue', blank=True)
def save(self, *args, **kwargs):
super(Product, self).save(*args, **kwargs)
print(AttributeValue.objects.all()) #like this

Django form, change default max_length

Within the model "Example" I have two fields:
-"description" (varchar, length 64).
-"description_length" integer.
description_length has different value for each record, and it is always between 1 and 64.
In a Django form how is possible set the maxlength description equal to the description_length variable value?
Sure thing.
class ExampleForm(forms.ModelForm):
class Meta:
model = Example
def __init__(self, *args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['description'].max_length = self.instance.description_length
Just be sure your description model field is big enough to accomodate the text of description_length:
class Example(models.Model):
MAX_DESCRIPTION_LENGTH = 1024
description = models.CharField(max_length=MAX_DESCRIPTION_LENGTH)
description_length = models.IntegerField(
validators=MaxValueValidator(MAX_DESCRIPTION_LENGTH))

How to solve ValueError When save ModelMultipleChoiceField in ModelForm?

My model.py:
class RelayAddress(models.Model):
id = models.AutoField(primary_key=True,default=0)
sister_relay_relation = models.ManyToManyField('self', through='RelaySisterRelation',symmetrical=False)
def save(self, *args, **kwargs):
self.update_time = int(time.time())
super(RelayAddress,self).save(*args, **kwargs)
class RelaySisterRelation(models.Model):
id = models.AutoField(primary_key=True,default=0)
relay = models.ForeignKey(RelayAddress,related_name="relay")
sister_relay = models.ForeignKey(RelayAddress,related_name="sister_relay")
My admin.py
class RelaySisterRelationForm(forms.ModelForm):
relay=forms.ModelMultipleChoiceField(label=u'relay',widget=forms.CheckboxSelectMultiple(),queryset=RelayAddress.objects.all())
sister_relay=forms.ModelMultipleChoiceField(label=u'sister_relay',widget=forms.CheckboxSelectMultiple(),queryset=RelayAddress.objects.all())
def save(self, *args, **kwargs):
return super(RelaySisterRelationForm, self).save(*args,**kwargs)
And my view.py is null, then I get a ValueError:
Cannot assign "[<RelayAddress: RelayAddress object>]": "RelaySisterRelation.relay" must be a "RelayAddress" instance.
And how to solve this problem.
RelaySisterRelation.relay is a ForeignKey to RelayAddress meaning it can only store a references to one RelayAddress but your RelaySisterRelationForm.relay uses ModelMultipleChoiceField which is for many-to-many relations so returns a (potentially empty) list of RelayAddress instances.

Store form fields as key-values / individual rows

I have a simple form in Django that looks like this:
class SettingForm(forms.Form):
theme = forms.CharField(rrequired=True,
initial='multgi'
)
defaultinputmessage = forms.CharField(required=True,
initial='Type here to begin..'
)
...and the model to store it looks like:
class Setting(models.Model):
name = models.CharField(
null=False, max_length=255
)
value= models.CharField(
null=False, max_length=255
)
When the form is submitted, how can i store the form fields as key value pairs and then when the page is rendered, how can I initialize the form with the key's value. I've tried looking for an implementation of this but have been unable to find one.
Any help?
Thanks.
I'm assuming you want to store 'theme' as the name and the value as the value, same for defaultinputmessage. If that's the case, this should work:
form = SettingForm({'theme': 'sometheme', 'defaultinputmessage': 'hello'})
if form.is_valid():
for key in form.fields.keys():
setting = Setting.objects.create(name=key, value=form.cleaned_data[key])
Here's how I did it.
I needed to do this because I had a Model that stored information as key value pairs and I needed to build a ModelForm on that Model but the ModelForm should display the key-value pairs as fields i.e. pivot the rows to columns. By default, the get() method of the Model always returns a Model instance of itself and I needed to use a custom Model. Here's what my key-value pair model looked like:
class Setting(models.Model):
domain = models.ForeignKey(Domain)
name = models.CharField(null=False, max_length=255)
value = models.CharField(null=False, max_length=255)
objects = SettingManager()
I built a custom manager on this to override the get() method:
class SettingManager(models.Manager):
def get(self, *args, **kwargs):
from modules.customer.proxies import *
from modules.customer.models import *
object = type('DomainSettings', (SettingProxy,), {'__module__' : 'modules.customer'})()
for pair in self.filter(*args, **kwargs): setattr(object, pair.name, pair.value)
setattr(object, 'domain', Domain.objects.get(id=int(kwargs['domain__exact'])))
return object
This Manager would instantiate an instance of this abstract model. (Abstract models don't have tables so Django doesn't throw up errors)
class SettingProxy(models.Model):
domain = models.ForeignKey(Domain, null=False, verbose_name="Domain")
theme = models.CharField(null=False, default='mytheme', max_length=16)
message = models.CharField(null=False, default='Waddup', max_length=64)
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
super(SettingProxy, self).__init__(*args, **kwargs)
for field in self._meta.fields:
if isinstance(field, models.AutoField):
del field
def save(self, *args, **kwargs):
with transaction.commit_on_success():
Setting.objects.filter(domain=self.domain).delete()
for field in self._meta.fields:
if isinstance(field, models.ForeignKey) or isinstance(field, models.AutoField):
continue
else:
print field.name + ': ' + field.value_to_string(self)
Setting.objects.create(domain=self.domain,
name=field.name, value=field.value_to_string(self)
)
This proxy has all the fields that I'd like display in my ModelFom and store as key-value pairs in my model. Now if I ever needed to add more fields, I could simply modify this abstract model and not have to edit the actual model itself. Now that I have a model, I can simply build a ModelForm on it like so:
class SettingsForm(forms.ModelForm):
class Meta:
model = SettingProxy
exclude = ('domain',)
def save(self, domain, *args, **kwargs):
print self.cleaned_data
commit = kwargs.get('commit', True)
kwargs['commit'] = False
setting = super(SettingsForm, self).save(*args, **kwargs)
setting.domain = domain
if commit:
setting.save()
return setting
I hope this helps. It required a lot of digging through the API docs to figure this out.

Categories

Resources