I have a model, course, with an ImageField and FileField so I’d like to create a folder each time the user create a course. I think I can do this before the model is saved so here is my question.
How can I access a model’s fields in a method?
Models.py
Class Course(models.Model):
Thumbnail = model.ImageField(upload_to=“...”,...)
def save(self, *args, **kwargd):
... #How can I alter here the ImageField parameters?
super().save(*args, **kwargs)
See here on getting the model's fields.
To get field of an object instance then it should just be as
def save(self, *args, **kwargs):
#### How can I alter here the ImageField parameters?
self.Thumbnail = #do whatever you want here
super().save(*args, **kwargs)
It's not possible to alter field's params in a method. It must only be done in the field definitions because the model must be saved first
Instance of the models field can be accessed using self like a normal instance variable.
For example in a model class below,
class DummyModel(models.Model):
key = models.CharField()
value = models.TextField()
def save(self, *args, **kwargs):
value = self.value # self.value is a model field.
super().save(*args, **kwargs)
In your case, you can access it using self.Thumbnail
Since it's not possible to modify the model field's parameters before create it, as #azyCrw4282 said in his answer, it's possible to create a directory with the name of the model's instance and upload there the files parsing a function to upload_to
models.py
def upload_to(instance, filename):
return 'user_course/{0}/{1}'.format(instance.name, filename) #instance.name will be the name of the course
class Course(models.Model):
name = model.CharField(...)
thumbnail = models.ImageField(upload_to=upload_to, ...)
Related
I want to get value from foreign key from another model and subscribe it.
It works when field is declared as ForeignKey but when field is declared as ManyToManyField it not works.
How can I do it?
Please help.
class Document(models.Model):
project = models.ForeignKey(Project)
text = models.ForeignKey(Text, null=True, blank=True)
language = models.ManyToManyField(Language, null=True, blank=True)
def save(self, *args, **kwargs):
self.text = self.project.text #WORKS
self.language = self.project.language.all() #NOT WORKS
super(Document, self).save(*args, **kwargs)
Does something like this works?
class Document(models.Model):
project = models.ForeignKey(Project)
text = models.ForeignKey(Text, null=True, blank=True)
languages = models.ManyToManyField(Language) # no need to null/blank + put the name on plural if using a many to many relation.
def save(self, *args, **kwargs):
self.text = self.project.text
super(Document, self).save(*args, **kwargs)
# super() must be called BEFORE feeding your many to many.
project_languages = self.project.languages.all()
self.languages.add(*project_languages)
When using a many to many field attribute, you need to wait for your instance is created before adding values in your many to many attribute.
You do this with add, contrary to foreign key fields.
You need to use .add() for initializing ManyToManyField
Change this line
# use plural naming convention when its ManyToMany relation `language` should be `languages` in your Document model
self.language = self.project.language.all()
to
# call save method of super class before adding values to many-to-many
super(Document, self).save(*args, **kwargs)
p_language = self.project.language.all()
self.language.add(*p_language)
So you must call save before adding the many-to-many relationship. Since add immediately affects the database, you do not need to save afterwards.
I would like to create some instance variables for my model subclass, but when saving the object to the database I don't want a table column for that variable. I read in some places you would do this by overriding init() like how you would create normal instance variables in other classes. Is this the accepted way for subclasses of model? Are there other approaches?
models.py:
class MyModel (models.Model):
name = models.CharField(max_length=300)
def __init__(self, *args, **kwargs):
super(MyModel, self).__init__(*args, **kwargs)
self.tempvar = ''
views.py:
myModel = MyModel()
myModel.tempvar = 'this will not be saved in the database'
That's an acceptable way of doing it, although you don't need to initialize it unless there's a chance you may try to access it when it doesn't exist. Also, consider if you should be using a property instead.
Update for Python 3: You can call super() directly without repeating the class name
class MyModel (models.Model):
name = models.CharField(max_length=300)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tempvar = ''
I have a ModelForm with a FileField, among other fields. I wanted to modify the filename on calling myform.save() to avoid collisions (insert 6 random characters to the filename). What's the proper way to do this in Django?
You need to override your Model's save method, not your Form's.
class MyModel(models.Model):
# other fields
my_file = models.FileField(upload_to='uploaddir')
def save(self, *args, **kwargs):
new_name = 'file_name-random-chars.ext'
self.my_file.name = new_name
super(MyModel, self).save(*args, **kwargs)
Your ModelForm for MyModel will call it's model's save method and do the trick.
Hope it helps :)
I am using BooleanField in Django.
By default, the checkbox generated by it is unchecked state. I want the state to be checked by default. How do I do that?
If you're just using a vanilla form (not a ModelForm), you can set a Field initial value ( https://docs.djangoproject.com/en/2.2/ref/forms/fields/#django.forms.Field.initial ) like
class MyForm(forms.Form):
my_field = forms.BooleanField(initial=True)
If you're using a ModelForm, you can set a default value on the model field ( https://docs.djangoproject.com/en/2.2/ref/models/fields/#default ), which will apply to the resulting ModelForm, like
class MyModel(models.Model):
my_field = models.BooleanField(default=True)
Finally, if you want to dynamically choose at runtime whether or not your field will be selected by default, you can use the initial parameter to the form when you initialize it:
form = MyForm(initial={'my_field':True})
from django.db import models
class Foo(models.Model):
any_field = models.BooleanField(default=True)
I am using django==1.11. The answer get the most vote is actually wrong. Checking the document from django, it says:
initial -- A value to use in this Field's initial display. This value
is not used as a fallback if data isn't given.
And if you dig into the code of form validation process, you will find that, for each fields, form will call it's widget's value_from_datadict to get actual value, so this is the place where we can inject default value.
To do this for BooleanField, we can inherit from CheckboxInput, override default value_from_datadict and init function.
class CheckboxInput(forms.CheckboxInput):
def __init__(self, default=False, *args, **kwargs):
super(CheckboxInput, self).__init__(*args, **kwargs)
self.default = default
def value_from_datadict(self, data, files, name):
if name not in data:
return self.default
return super(CheckboxInput, self).value_from_datadict(data, files, name)
Then use this widget when creating BooleanField.
class ExampleForm(forms.Form):
bool_field = forms.BooleanField(widget=CheckboxInput(default=True), required=False)
In Django 3.0 the default value of a BooleanField in model.py is set like this:
class model_name(models.Model):
example_name = models.BooleanField(default=False)
I found the cleanest way of doing it is this.
Tested on Django 3.1.5
class MyForm(forms.Form):
my_boolean = forms.BooleanField(required=False, initial=True)
I found the answer here
Another way to check the default state in BooleanField is:
active = forms.BooleanField(
widget=forms.CheckboxInput(
attrs={
'checked': True
}
)
)
Both initial and default properties were not working for me, if that's your case try this:
class MyForm(forms.ModelForm):
validated = forms.BooleanField()
class Meta:
model = MyModel
fields = '__all__'
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['validated'].widget.attrs['checked'] = True
I tried to change inital of BooleanField:
def __init__(self, *args, **kwargs):
super(UserConfirmForm,self).__init__(*args, **kwargs)
self.fields['bool_field'].initial = True
but it didn't work.
My solve:
def __init__(self, *args, **kwargs):
kwargs['initial'] = {'bool_field': True}
super(UserConfirmForm,self).__init__(*args, **kwargs)
It works like:
UserConfirmForm(initial={'bool_field':True})
but we can't call form in Generic editing views.
I think this is a great alternative to a regular call form object.
I'm configuring the admin site of my new project, and I have a little doubt on how should I do for, on hitting 'Save' when adding data through the admin site, everything is converted to upper case...
Edit: Ok I know the .upper property, and I I did a view, I would know how to do it, but I'm wondering if there is any property available for the field configuration on the admin site :P
If your goal is to only have things converted to upper case when saving in the admin section, you'll want to create a form with custom validation to make the case change:
class MyArticleAdminForm(forms.ModelForm):
class Meta:
model = Article
def clean_name(self):
return self.cleaned_data["name"].upper()
If your goal is to always have the value in uppercase, then you should override save in the model field:
class Blog(models.Model):
name = models.CharField(max_length=100)
def save(self, force_insert=False, force_update=False):
self.name = self.name.upper()
super(Blog, self).save(force_insert, force_update)
Updated example from documentation suggests using args, kwargs to pass through as:
Django will, from time to time, extend the capabilities of built-in
model methods, adding new arguments. If you use *args, **kwargs in
your method definitions, you are guaranteed that your code will
automatically support those arguments when they are added.
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
do_something()
super(Blog, self).save( *args, **kwargs) # Call the "real" save() method.
do_something_else()
you have to override save(). An example from the documentation:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, force_insert=False, force_update=False):
do_something()
super(Blog, self).save(force_insert, force_update) # Call the "real" save() method.
do_something_else()