Adding custom field and updating model problem in django - django

I need to add a colorpicker to my django model and wrote a custom widget. However when I add this colordfield to my model, django gives this error:
column mediaplanner_ievent.color does not exist
LINE 1: ...nt"."bits", "mediaplanner_ievent"."capture_link", "mediaplan...
My model is :
from mediaplanner.custom_widgets import ColorPickerWidget
class ColorField(models.CharField):
def __init__(self,*args, **kwargs):
kwargs['max_length'] = 10
super(ColorField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
kwargs['widget'] = ColorPickerWidget
return super(ColorField, self).formfield(**kwargs)
class iEvent(models.Model):
name = models.CharField(verbose_name= u"Uygulama Adı", max_length=100, unique=True)
bits = models.CommaSeparatedIntegerField(verbose_name= u"Bitler",max_length=100)
capture_link = models.URLField(verbose_name= u"Capture URL", null=True, blank=True)
color = ColorField(blank=true)
class Meta:
verbose_name = u"red button"
verbose_name_plural = u"red buttonlar"
def __unicode__(self):
return smart_str( "%s"% self.name )
The strange thing is, when I looked my database, there exist colorfield. I don't want to delete the db and load it again. But ofcourse if it's the only solution, then no choice ..
So someone can help me how to solve it?

The field in your database is named colorfield bu the field in your model is named color. You have to change one or the other to make it work again.

Related

Update datetimefiled of all related models when model is updated

I have two models (Post and Display). Both have Datetime-auto fields. My problem is that i want to update all display objects related to a post, once a post is updated.
I have read here that you could override one models save method, but all the examples are About updating the model with the foreign key in it and then call the save method of the other model. In my case it's the other way arround. How can i do this ?
class Post(models.Model):
title = models.CharField(max_length=40)
content = models.TextField(max_length=300)
date_posted = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rooms = models.ManyToManyField(Room, related_name='roomposts', through='Display')
def __str__(self):
return self.title
def get_absolute_url(self):
return "/post/{}/".format(self.pk)
class Display(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
isdisplayed = models.BooleanField(default=0)
date_posted = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.isdisplayed)
i want to update the date_posted of all related Display-objects once their related post is changed. I do not know if overriding the save-method works here.
in this case you should have a look at django's reverse foreign key documentation
https://docs.djangoproject.com/en/2.2/topics/db/queries/#following-relationships-backward
in your case you can override the save method on your Post model
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
#either: this excutes many sql statments
for display in self.display_set.all():
display.save()
#or faster: this excute only one sql statements,
#but note that this does not call Display.save
self.display_set.all().update(date_posted=self.date_posted)
The name display_set can be changed using the related_name option
in Display, you can change it:
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='displays')
Then, instead of using self.display_set in your code, you can use self.displays
Overriding save method works, but that's not were you should go, imo.
What you need is signals:
#receiver(post_save, sender=Post)
def update_displays_on_post_save(sender, instance, **kwargs):
if kwargs.get('created') is False: # This means you have updated the post
# do smth with instance.display_set
Usually it goes into signals.py.
Also you need to include this in you AppConfig
def ready(self):
from . import signals # noqa

How to limit choices to Foreign keys in Django admin

I run into a problem when using the Django admin. I'm building a small ScrumBoard. It has projects, with statuses, stories and tasks.
Consider the following model:
#python_2_unicode_compatible
class Project(models.Model):
name = models.CharField(max_length=100)
class Meta:
verbose_name = _('Project')
verbose_name_plural = _('Projects')
def __str__(self):
return self.name
#python_2_unicode_compatible
class Status(models.Model):
name = models.CharField(max_length=64) # e.g. Todo, In progress, Testing Done
project = models.ForeignKey(Project)
class Meta:
verbose_name = _('Status')
verbose_name_plural = _('Statuses')
def __str__(self):
return self.name
#python_2_unicode_compatible
class Story(models.Model):
"""Unit of work to be done for the sprint. Can consist out of smaller tasks"""
project = models.ForeignKey(Project)
name=models.CharField(max_length=200)
description=models.TextField()
status = models.ForeignKey(Status)
class Meta:
verbose_name = _('Story')
verbose_name_plural = _('Stories')
# represent a story with it's title
def __str__(self):
return self.name
The problem: when an admin user creates a story he will see statuses from all the projects instead of the status from one project.
To filter statuses by project, you need your story to already exist so django know which project we are talking about. If you set status nullalble, you can do like this (implying, you do save and continue on first save to set status)
class StatusAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super(StatusAdmin, self).get_form(request, obj, **kwargs)
if obj and obj.project:
form.base_fields['status'].queryset = \
form.base_fields['status'].queryset.filter(project=obj.project)
elif obj is None and 'status' in form.base_fields: # on creation
del form.base_fields['status']
return form
You will need something like django-smart-selects

Why doesn't my save method work in the admin?

In my model I overwrite the save-method for my blog model to auto-populate the slug field using the slugify method.
class BlogPost(models.Model):
title = models.CharField(max_length=100,unique=True)
slug = models.SlugField(max_length=100,unique=True)
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(Author)
body = models.TextField()
category = models.ForeignKey(BlogCategory)
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.slug = slugify(self.title)
super(BlogPost, self).save(*args, **kwargs)
But creating a new object in the admin interface doesn't work without either setting the slug field manually or doing something like
class BlogPostAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
Basically I currently have the same functionality defined twice. Any ideas on how to avoid this? And: why doesn't work my own save method in the admin?
You should put blank=True in the definition of the slug field.

How to hide model field in Django Admin?

I generate field automaticly, so I want to hide it from user. I've tried editable = False and hide it from exclude = ('field',). All this things hide this field from me, but made it empty so I've got error: null value in column "date" violates not-null constraint.
models.py:
class Message(models.Model):
title = models.CharField(max_length = 100)
text = models.TextField()
date = models.DateTimeField(editable=False)
user = models.ForeignKey(User, null = True, blank = True)
main_category = models.ForeignKey(MainCategory)
sub_category = models.ForeignKey(SubCategory)
groups = models.ManyToManyField(Group)`
admin.py:
class MessageAdminForm(forms.ModelForm):
def __init__(self, *arg, **kwargs):
super(MessageAdminForm, self).__init__(*arg, **kwargs)
self.initial['date'] = datetime.now()
class MessageAdmin(admin.ModelAdmin):
form = MessageAdminForm
list_display = ('title','user',)
list_filter = ('date',)
Based on your model setup, I think the easiest thing to do would change your date field to:
date = models.DateTimeField(auto_now=True)
that should accomplish what you're after and you don't even need to exclude it from the admin, it's excluded by default. If you have auto_now=True it will act as a 'last update time'. If you have auto_now_add=True it will act as a creation time stamp.
There are several other ways you could accomplish your goal if your use case is more complex than a simple auto date field.
Override the model's save method to put the value in.
class Message(models.Model):
title=models.CharField(max_length=100)
date = models.DateTimeField(editable=False)
def save(*args, **kwargs):
self.date = datetime.datetime.now()
super(Message, self).save(*args, **kwargs)
What you are trying to do with the Model Admin isn't quite working because by default django only transfers the form fields back to a model instance if the fields are included. I think this might be so the model form doesn't try to assign arbitrary attributes to the model. The correct way to accomplish this would be to set the value on the instance in your form's save method.
class MessageAdminForm(forms.ModelForm):
def save(*args, **kwargs):
self.instance.date = datetime.now()
return super(MessageAdminForm, self).save(*args, **kwargs)

Django Model Inheritance and limit_choices_to

Can anyone tell me how i can limit the choices for the Page model which i inherit from in the following code?
class CaseStudy(Page):
"""
An entry in a fancy picture flow widget for a case study page
"""
image = models.ForeignKey(Image, limit_choices_to={'is_active': True, 'category__code':'RP'})
def __unicode__(self):
return u"%s" % self.title
The django admin is limiting the image choices in a drop down successfully, but i would like to limit a field in the Page model as well (a 'parent page field'), ie:
class Page(models.Model):
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
I managed to work this out - by overriding the admin model form. I realise this could be tightened up, but thought it might come in use to someone out there. Here's an excerpt from the admin.py
class CaseStudyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CaseStudyForm, self).__init__(*args, **kwargs)
recent_project_page = Page.objects.get(title="Recent Projects")
parent_widget = self.fields['parent'].widget
choices = []
for key, value in parent_widget.choices:
if key in [recent_project_page.id,]:
choices.append((key, value))
parent_widget.choices = choices
class CaseStudyAdmin(admin.ModelAdmin):
form = CaseStudyForm
admin.site.register(CaseStudy, CaseStudyAdmin)