I have a model class, and I want to pass the instance to a method from within this class model:
class myModel(models.Model):
id = models.AutoField()
...several fields...
user= models.CharField(max_length=50, db_column='user', editable=False) # Field name made lowercase.
myFile = models.FileField(max_length=256, blank=True, upload_to=create_file_name(instance, myString))
If I want to define a method create_file_name with one of the params the model instance itself, I don't know how to refer to it.
I know that if I just call upload_to=create_file_name with no params, the method takes automatically instance and filename, but I want to pass the instance and a specific string (not the filename).
Thanks.
Try this instead:
upload_to = lambda instance, filename : create_file(instance, 'whatever')
Related
This code is a abstract class for many
Class Base (models.Model):
Created_by = models.ForeignKey(User)
Modified_by = models.ForeignKey(User, null=True)
I want related_name like this related_name = self.default_related_name + '_name_field'
As the following
Class Base(models.Model):
Created_by = models.ForeignKey(User,
related_name = self.default_related_name + '_created_by')
Modified_by = models.ForeignKey(User,
null = True,
related_name = self.default_related_name + '_modified_by')
But i know that, I cant have access to instance in the attributes of the class.
So what method do I can to overload to create a field with a method (or property)?
(I tried to create the field in the __init__ method, but it doesnt not work).
If you can use the subclass name instead of default_related_name then it's trivial:
related_name="%(class)s_created"
https://docs.djangoproject.com/en/1.8/topics/db/models/#be-careful-with-related-name
Also, as the base class is a abstract model, you will need
class Meta:
abstract = True
Pre save signal is what you are looking for.
for reference : https://docs.djangoproject.com/en/1.11/ref/signals/#pre-save
right before save it to the database, you can apply all the changes you want. :)
here is an example where I capitalize the first letter of every word and create a slug.
def pre_save_city(sender, instance, *args, **kwargs):
instance.name = instance.name.title()
if not instance.slug:
instance.slug = slugify(instance.name)
this is how you run the function :
pre_save.connect(pre_save_city,sender=City)
I want to set a non-persistent property on a model. I have tried the following:
class class User(models.Model):
email = models.EmailField(max_length=254, unique=True, db_index=True)
#property
def client_id(self):
return self.client_id
Then:
user = User.objects.create(email='123', client_id=123)
print(user.client_id)
I get the error: can't set attribute. Why?
You need to define a setter function for your property too, right now, it is read-only (see, e.g., this question).
class class User(models.Model):
email = models.EmailField(max_length=254, unique=True, db_index=True)
#property
def client_id(self):
return self.internal_client_id
#client_id.setter
def client_id(self, value):
self.internal_client_id = value
Note that I renamed self.client_id to self.internal_client_id, because otherwise, you would be calling the getter and setter functions recursively - the name of the internal variable needs to be different from the property's name.
Of course, if you need to use self.client_id (e.g. because of inheritance), you can also rename the property itself.
models.py
from django.db import models
from alpha_id import get_alpha_id
class Sample(models.Model):
alpha_id = get_alpha_id(self.id)
sample_name = models.CharField(max_length=30)
entry_date = models.DateField(auto_now_add=True)
def __unicode__(self):
return self.alpha_id
alpha_id.py
import string
ALL_LETTERS = string.ascii_uppercase.replace('F', '').replace('I', '').replace('L', '').replace('O', '').replace('V', '')
def get_alpha_id(id):
""" Return the alpha numeric ID according to the current
integer id.
"""
global ALL_LETTERS
alpha = ALL_LETTERS[(id%len(ALL_LETTERS))-1]
return str(id) + '_' + alpha
Here, I am trying to create a alpha_id model attribute which establishes an alpha numeric id based on the automatically created integer id attribute. I wrote a function that performs the algorithm, and I just need to send that method the id of the current instantiated model. For example:
>>> get_alpha_id(1)
1_A
>>>get_alpha_id(2)
2_B
Anyways I have that logic all figured out. All i need to do is figure out how to pass to that function the id attribute of the current instantiation of my Sample model.
Obviously my problem here is that I am not referring to an instantiation of the class Sample, so the use of "self.id" is causing an error. To be specific:
alpha_id = get_alpha_id(self.id)
NameError: name 'self' is not defined
I have a feeling the solution involves something to do with defining an __init__method but I am not quite sure how I would go about doing it. I have looked at the Model.py base class and I couldn't quite find where the id attribute is defined.
To sum it up, how can I access the current id of an instantiated django model so that I can use that integer value to inform the creation of another attribute?
Instead of making alpha_id a class attribute, you need to make it an instance attribute using the #property decorator on an instance method:
class Sample(models.Model):
sample_name = models.CharField(max_length=30)
entry_date = models.DateField(auto_now_add=True)
#property
def alpha_id(self):
return get_alpha_id(self.id)
def __unicode__(self):
return self.alpha_id
I am using PyCharm 4.5.2, Django 1.8.2.
If I define a class as:
class User(models.Model):
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
slug = models.SlugField(max_length=256, unique=True, default=make_slug)
def make_slug(self):
return self.first_name + self.last_name[0]
The IDE highlights default=make_slug with make_slug being undefined. The interpretter agrees and when the development server tries to refresh it exits with status 1 and the error NameError: name 'make_slug' is not defined.
Because it's just the name of a callable, I can't pass arguments. So if I define the function outside the class (to move into a higher scope and be defined) I can't use the class properties. I have read some suggestions that use lambdas but from the Django documentation that is wrong:
Note that lambdas cannot be used for field options like default
because they cannot be serialized by migrations. See that
documentation for other caveats.
What is the proper way to define a callable for default values in a model.
You shouldn't use this method to set your default value, rather than override the save method of the model and use it there. For example:
class User(models.Model):
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
slug = models.SlugField(max_length=256, unique=True, default=uuid.uuid1)
def make_slug(self):
return self.first_name + self.last_name[0]
def save(self, *args, **kwargs):
self.slug = self.make_slug()
super().save(*args, **kwargs)
You get this error
NameError: name 'make_slug' is not defined.
because you refer to make_slug before you defined it. If you moved the make_slug function above the slug field, then you wouldn't get that error.
However, it isn't possible to pass any arguments to the callable that you use as the default, so that won't work either. You can't get around that restriction by using a model method as you are trying.
If you need access to the model instance to calculate the default, then setting the value in the save() method as ruddra suggests is a good idea. Note that you might want to check whether or not the model has a primary key, so that you only create the slug when you first create the instance.
I'm developing Django application, and I have following error
'Sheep' object has no attribute _state
My models are constructed like this
class Animal(models.Model):
aul = models.ForeignKey(Aul)
weight = models.IntegerField()
quality = models.IntegerField()
age = models.IntegerField()
def __init__(self,aul):
self.aul=aul
self.weight=3
self.quality=10
self.age=0
def __str__(self):
return self.age
class Sheep(Animal):
wool = models.IntegerField()
def __init__(self,aul):
Animal.__init__(self,aul)
What I must do?
firstly, you must be very careful overriding __init__ to have non-optional arguments. remember it will be called every time you get an object from a queryset!
this is the correct code you want:
class Animal(models.Model):
#class Meta: #uncomment this for an abstract class
# abstract = True
aul = models.ForeignKey(Aul)
weight = models.IntegerField(default=3)
quality = models.IntegerField(default=10)
age = models.IntegerField(default=0)
def __unicode__(self):
return self.age
class Sheep(Animal):
wool = models.IntegerField()
I highly suggest setting the abstract option on Animal if you will only ever be using subclasses of this object. This ensures a table is not created for animal and only for Sheep (etc..). if abstract is not set, then an Animal table will be created and the Sheep class will be given it's own table and an automatic 'animal' field which will be a foreign key to the Animal model.
Django docs recommend against you to use __init__ method in models:
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved. Rather than overriding __init__, try using one of these approaches:
Add a classmethod on the model class
Add a method on a custom manager (usually preferred)