i am developing a django custom field . Inside the custom field def, how can i write some code that saves another field ? For example, inside the def of custom field, I have written pre_save method but after assigning values to other model fields, I have called model_instance.save() method but that resulted in an infinite loop. Can you tell me how to do this ?
class FullNameField(models.CharField):
def contribute_to_class(self, cls, name):
firstname_field = models.CharField(
null=True, blank=True, max_length=50)
lastname_field = models.CharField(
null=True, blank=True, max_length=50)
firstname_field.creation_counter = self.creation_counter
lastname_field.creation_counter = self.creation_counter
cls.add_to_class('firstname', firstname_field )
cls.add_to_class('lastname', lastname_field )
super(FullNameField, self).contribute_to_class(cls, name)
The above code successfully creates the new fields firstname and lastname during syncdb, wha t i want to do is, when i populate the fullnamefield, firstname and lastname should also be populated. This fullname logic is just an example, but the requirement is same.
You can use the pre_save signal to get notified when the class is saved.
Add this to your contribute_to_class method:
from django.db.models.signals import pre_save
def populate_fullname(sender, instance, raw, **kwargs):
if raw:
return # be nice to syncdb
fullname = u'%s %s' % (instance.firstname, instance.lastname))
setattr(instance, name, fullname)
pre_save.connect(populate_fullname, cls)
Related
I have a model which is refered to as a foreignkey with on_delete set to SET_DEFAULT. Because of that, I need to provide this model with a default item. I created a static method which does just that.
class ScheduleChoice(models.Model):
"""
This model allows users to define crontab schedules.
"""
label = models.CharField(max_length=256, verbose_name="Label", unique=True)
job_schedule = models.CharField(
max_length=256,
default="0 0 * * *", verbose_name="Crontab"
)
#staticmethod
def get_default_schedule_choice():
"""
Because some models rely on ScheduleChoice and need a default value,
we need to give them a default ScheduleChoice.
"""
try:
choice = ScheduleChoice.objects.get_or_create(
label="Every minute",
job_schedule="* * * * *"
)
except ProgrammingError:
choice = None
return choice
#classmethod
def get_choice_count(cls):
"""
Returns how many schedule choices have been defined.
"""
return len(cls.objects.all())
class Meta:
verbose_name = "schedule choice"
verbose_name_plural = "schedule choices"
def __str__(self):
return self.label
class MyOtherModel(models.Model):
"""
Model using ScheduleChoices.
"""
job_schedule = models.ForeignKey(
"ScheduleChoice",
on_delete=models.SET_DEFAULT,
default=ScheduleChoice.get_default_schedule_choice(),
verbose_name="Schedule"
)
activated = models.BooleanField(default=False, verbose_name="activated")
I am able to run makemigrations and migrate without issue.
My problem starts when I modifiy my models and try to use makemigrations again in order to update the migrations files. I get the error :
ValueError: Cannot serialize: <ScheduleChoice: Every minute>
There are some values Django cannot serialize into migration files.
For more, see https://docs.djangoproject.com/en/2.2/topics/migrations/#migration-serializing
I tried to apply this answer, but it didn't help. Why does Django need to serialize my default value ? Why does it only do so after the first migration has successfully ended ?
I can always use reset_db and do my migration, but it is not acceptable in my production environment.
How can I fix this ?
Django needs to serialize your models to make migration files for them. Hence it also needs to serialize most of the attributes you set on the model fields (default included). Currently you define a method and directly call that instead of providing the method as the default, also your method returns a tuple with ScheduleChoice and a boolean.
Django can serialize booleans but not the model instance (for the migration) hence you get an error, not to mention the tuple would have caused an error anyway. You should not call the method and instead just pass the method as the default, also instead of returning the instance return only the pk, also ideally this method should simply be a function:
class ScheduleChoice(models.Model):
"""
This model allows users to define crontab schedules.
"""
label = models.CharField(max_length=256, verbose_name="Label", unique=True)
job_schedule = models.CharField(
max_length=256,
default="0 0 * * *", verbose_name="Crontab"
)
#classmethod
def get_choice_count(cls):
"""
Returns how many schedule choices have been defined.
"""
return len(cls.objects.all())
class Meta:
verbose_name = "schedule choice"
verbose_name_plural = "schedule choices"
def __str__(self):
return self.label
def get_default_schedule_choice():
choice, _created = ScheduleChoice.objects.get_or_create(
label="Every minute",
job_schedule="* * * * *"
)
# Why would programming error occur?
return choice.pk # Return the pk
class MyOtherModel(models.Model):
"""
Model using ScheduleChoices.
"""
job_schedule = models.ForeignKey(
"ScheduleChoice",
on_delete=models.SET_DEFAULT,
default=get_default_schedule_choice, # Don't call the function, only pass it
verbose_name="Schedule"
)
activated = models.BooleanField(default=False, verbose_name="activated")
Context: I'm forcing my self to learn django, I already wrote a small php based website, so I'm basically porting over the pages and functions to learn how django works.
I have 2 models
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Combo(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
dead = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
siteID = models.ForeignKey(Site, on_delete=models.PROTECT)
class Meta:
unique_together = ('username','siteID')
def __str__(self):
return f"{self.username}:{self.password}#{self.siteID.name}"
When creating a view, I want to get the Combo objects, but I want to sort them first by site name, then username.
I tried to create the view, but get errors about what fields I can order by Cannot resolve keyword 'Site' into field. Choices are: dead, id, password, siteID, siteID_id, timestamp, username
def current(request):
current = Combo.objects.filter(dead=False).order_by('Site__name','username')
return render(request, 'passwords/current.html',{'current':current})
Since I'm not necissarily entering the sites into the database in alphabetical order, ordering by siteID wouldn't be useful. Looking for some help to figure out how to return back the list of Combo objects ordered by the Site name object then the username.
You can order this by siteID__name:
def current(request):
current = Combo.objects.filter(dead=False).order_by('siteID__name','username')
return render(request, 'passwords/current.html',{'current':current})
since that is the name of the ForeignKey. But that being said, normally ForeignKeys are not given names that end with an ID, since Django already adds an _id suffix at the end for the database field.
Normally one uses:
class Combo(models.Model):
# …
site = models.ForeignKey(Site, on_delete=models.PROTECT)
if you want to give the database column a different name, you can specify that with the db_column=… parameter [Django-doc]:
class Combo(models.Model):
# …
site = models.ForeignKey(
Site,
on_delete=models.PROTECT,
db_column='siteID'
)
I want to add variable in Django model and I don't want to save it to database at the same time I want to return this variable to user when calling the endpoint.
this is what i found in the web, but the problem is the variable is not rerun to user
class User (models.Model):
f_name = models.CharField(max_length=255)
l_name = models.CharField(max_length=300)
full_name = ''
How to rerun the full_name to user when he call the api ?
If this is using Django Rest Framework, I don't know how your code is set up, but you'll need to extend your serializer:
add a new field to the serializer: full_name = serializers.SerializerMethodField()
add a method to the serializer:
def get_full_name(self, obj):
return "{} {}".format(obj.first_name, obj.last_name)
NOTE:
there are LOTS of different ways of joining those strings together, using #property in your model, fstrings, etc - up to you to choose the most appropriate for your needs (without seeing the rest of your code()
You can define model's property:
class User (models.Model):
f_name = models.CharField(max_length=255)
l_name = models.CharField(max_length=300)
#property
def full_name(self):
return self.f_name + self.l_name
now you use full_name same way as normal attribute user.full_name.
When I open an entry of "Placerating" in Admin, and try to save it after making a change to any field, Django admin displays "This field is required" above the field "Pic".
class Placerating(models.Model):
theplace = models.ForeignKey('ThePlace', on_delete=models.CASCADE, null=True, related_name='placeratings')
pic = models.OneToOneField('fileupload.Picture', on_delete=models.SET_NULL, null=True)
def __unicode__(self):
return self.theplace.name
class Picture(models.Model):
def set_upload_to_info(self, path, name):
self.upload_to_info = (path, name)
file = ImageField(max_length=500, upload_to=user_directory_path)
def filename(self):
return os.path.basename(self.file.name)
theplace = models.ForeignKey(ThePlace, null=True, blank=True, related_name='pictures')
def __unicode__(self):
return str(self.id)
def save(self, *args, **kwargs):
super(Picture, self).save(*args, **kwargs)
I created the entry without problem with a form, so I don't understand why admin would now require this field to be completed.
From the docs about the null argument to model fields:
For both string-based and non-string-based fields, you will also need
to set blank=True if you wish to permit empty values in forms, as the
null parameter only affects database storage (see blank).
The admin uses forms for creation and editing, so you need blank=True in the fields you want to be able to leave blank in the admin.
I have a model (Application) tied to a foreign_key (Person) table. I was having trouble getting the Person-dropdown in the admin to sort by name instead of by key, and found this Reorder users in django auth as a solution. However, this made the fields mandatory and I can't figure out how to get them to stay optional.
app/models.py
class Person(models.Model):
Full_Name = models.CharField(max_length=200)
def __unicode__(self):
return self.Full_Name
class Application(models.Model):
Name = models.CharField(max_length=100)
Primary_Contact = models.ForeignKey(Person,blank=True,null=True,related_name='appprimarycontact')
def __unicode__(self):
return self.Name
admin.py
class OwnerAdminForm(forms.ModelForm):
Primary_Contact = forms.ModelChoiceField(queryset=Person.objects.order_by('Full_Name'),)
class Meta:
model = Application
class ApplicationAdmin(admin.ModelAdmin):
form = OwnerAdminForm
list_display = ('Name','Primary Contact')
Just add the required=False option on the form field
forms.ModelChoiceField(required=False, queryset=Person.objects.order_by('Full_Name'))
The thing is, if you override the default form widget that django's ModelForm would provide, you would have to explicitly specify required=False, since the default value is True