django admin gives warning "Field 'X' doesn't have a default value" - django

I have created two models out of an existing legacy DB , one for articles and one for tags that one can associate with articles:
class Article(models.Model):
article_id = models.AutoField(primary_key=True)
text = models.CharField(max_length=400)
class Meta:
db_table = u'articles'
class Tag(models.Model):
tag_id = models.AutoField(primary_key=True)
tag = models.CharField(max_length=20)
article=models.ForeignKey(Article)
class Meta:
db_table = u'article_tags'
I want to enable adding tags for an article from the admin interface, so my admin.py file looks like this:
from models import Article,Tag
from django.contrib import admin
class TagInline(admin.StackedInline):
model = Tag
class ArticleAdmin(admin.ModelAdmin):
inlines = [TagInline]
admin.site.register(Article,ArticleAdmin)
The interface looks fine, but when I try to save, I get:
Warning at /admin/webserver/article/382/
Field 'tag_id' doesn't have a default value

This can also happen if you have a disused field in your database that doesn't allow NULL.

The problem was that in the DB, tag_id wasn't set as an autoincrement field.

What solved this issue in my case was disabling STRICT_TRANS_TABLES SQL mode which was enabled by default.

Related

Model field missing in admin

The invoice_date field on one of my models is not showing up in my admin.
invoice_date = models.DateField(auto_now=True, auto_now_add=False, null=True, blank=True)
I've tried the following:
renaming the field
running makemigrations/migrations
restarting the server
deleting cookies
I can successfully write to the field and pull data from it, so it appears to be there and functioning as desired. I just can't see it in the admin.
I have no special code in my admin.py. I've just registered the model
admin.py
from userorders.models import UserCartItem
admin.site.register(UserCart)
Any suggestions are welcome! Thanks!
Accoring to Django's documentation:
As currently implemented, setting auto_now or auto_now_add to True will cause the field to have editable=False and blank=True set.
You can circumvent this by explicitly defining it on the ModelAdmin class:
from userorders.models import UserCartItem
class UserCartItemAdmin(admin.ModelAdmin):
list_display = ['invoice_date']
fields = ['invoice_date']
# if you want the field just to visible but not editable
# readonly_fields = ['invoice_date']
admin.site.register(UserCartItem, UserCartItemAdmin)
You could try something following-
from userorders.models import UserCartItem
class UserCartItemAdmin(admin.ModelAdmin):
list_display = ['field_name_1', 'field_name_2', 'invoice_date']
admin.site.register(UserCartItem, UserCartItemAdmin)

Django: how to get related foreign key set?

I'm working in Django 1.8. I have models like this:
class School(models.Model):
code = models.CharField(primary_key=True)
name = models.CharField(max_length=200)
class Meta:
app_label = 'frontend'
class SchoolStatusOnDate(models.Model):
school = models.ForeignKey(School)
date = models.DateField()
setting = models.IntegerField()
I want to retrieve all the statuses associated with a particular school, and I think I should be able to do it using _set as described here, but it isn't working. This is my code:
s = School.objects.filter(code='A81018')
now = datetime.datetime.now()
SchoolStatusOnDate.objects.create(school=s, date=now, setting=4)
print s.schoolStatusOnDate_set.all()
But this gives me the following error on the final line:
AttributeError: 'School' object has no attribute 'schoolStatusOnDate_set'
What am I doing wrong?
schoolStatusOnDate_set should be lowercase.
From Django documentation: Following relationships “backward”:
If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased.
(emphasis mine)

Add other object and receive error MultiValueDictKeyError (Django admin)

I have a relationship follow as:
class Question(models.Model):
qid = models.PositiveIntegerField(primary_key=True)
content = models.CharField(max_length=128)
class Answer(models.Model):
answerid = models.PositiveIntegerField(primary_key=True)
content = models.CharField(max_length=128)
question = models.ForeignKey(Question)
class AnswerInline(admin.StackedInline):
model = Answer
readonly_fields = ('answerid',)
extra = 0
class QuestionAdmin(admin.ModelAdmin):
inlines = [AnswerInline]
exclude = ('id')
list_display = ('content',)
admin.site.register(Question,QuestionAdmin)
Suppose I have a question namely A and I haven't any answer for this question yet.
So, when I add an answer of A. It's ok. However, I try to add an other answer, system output an error MultiValueDictKeyError:
"Key 'oam_answer_set-0-answerid' not found in QueryDict:...
Because both of 'qid' and 'answerid' are not an AutoField. So, when I save an object, django admin can not insert a new row into database (missing primary key).
The AutoField is declared an IntegerField. However, I would like the field type of primary key is PositiveIntegerField. For that reason, how can I customize an AutoField?
Thanks
Try registering the Answer model with the admin i.e.
...
admin.site.register(Answer)
at the bottom of the admin.py. You are using fields on the inline (specifically readonly_fields) that are inherited from ModelAdmin, but you might not have registered that model.

Error using a base class field in subclass unique_together meta option

Using the following code:
class Organization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
...
class Division(Organization):
parent_org = models.ForeignKey(Organization)
class Meta:
unique_together=['parent_org', 'alias']
...
Trying to syncdb give me this error:
Error: One or more models did not validate:
organizations.division: "unique_together" refers to alias. This is not in the
same model as the unique_together statement.
Any help is appreciated,
Thanks,
Eric
This is by design. Reading the documentation for the unique_together option, it states that:
It's used in the Django admin and is enforced at the database level.
If you look at the table that a subclass creates, you'll see that it doesn't actually have the fields that its parent has. Instead, it gets a soft Foreign Key to the parent table with a field name called [field]_ptr_id, where [field] is the name of the table you're inheriting from excluding the app name. So your division table has a Primary Foreign Key called organization_ptr_id.
Now because unique_together is enforced at the database level using the UNIQUE constraint, there's no way that I know of for the database to actually apply that to a field not in the table.
Your best bet is probably through using Validators at your business-logic level, or re-thinking your database schema to support the constraint.
Edit: As Manoj pointed out, you could also try using Model Validators such as validate_unique.
[Model] Validators would work for you. Perhaps simplest, though, would be to use:
class BaseOrganization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
class Meta:
abstract = True
class Organization(BaseOrganization):
pass
class Division(BaseOrganization):
parent_org = models.ForeignKey(Organization)
class Meta:
unique_together=['parent_org', 'alias']
Note: as with your current code, you could not have subdivisions of divisions.
This is a solution I recently used in Django 1.6 (thanks to Manoj Govindan for the idea):
class Organization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
...
class Division(Organization):
parent_org = models.ForeignKey(Organization)
# override Model.validate_unique
def validate_unique(self, exclude=None):
# these next 5 lines are directly from the Model.validate_unique source code
unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
errors = self._perform_unique_checks(unique_checks)
date_errors = self._perform_date_checks(date_checks)
for k, v in date_errors.items():
errors.setdefault(k, []).extend(v)
# here I get a list of all pairs of parent_org, alias from the database (returned
# as a list of tuples) & check for a match, in which case you add a non-field
# error to the error list
pairs = Division.objects.exclude(pk=self.pk).values_list('parent_org', 'alias')
if (self.parent_org, self.alias) in pairs:
errors.setdefault(NON_FIELD_ERRORS, []).append('parent_org and alias must be unique')
# finally you raise the ValidationError that includes all validation errors,
# including your new unique constraint
if errors:
raise ValidationError(errors)
This does not strictly apply the question but is very closely related; unique_together will work if the base class is abstract. You can mark abstract model classes as such using:
class Meta():
abstract = True
This will prevent django from creating a table for the class, and its fields will be directly included in any subclasses. In this situation, unique_together is possible because all fields are in the same table.
https://docs.djangoproject.com/en/1.5/topics/db/models/#abstract-base-classes
I had similar challenge when trying to apply unique_together to a permission group created by a given client.
class ClientGroup(Group):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
is_active = models.BooleanField()
class Meta():
# looking at the db i found a field called group_ptr_id.
# adding group_ptr did solve the problem.
unique_together = ('group_ptr', 'client', 'is_active')

Django: list_filter and foreign key fields

Django doesn't support getting foreign key values from list_display or list_filter (e.g foo__bar). I know you can create a module method as a workaround for list_display, but how would I go about to do the same for list_filter? Thanks.
Django supports list_filter with foreign key fields
# models.py:
class Foo(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return self.name
class Bar(models.Model):
name = models.CharField(max_length=255)
foo = models.ForeignKey(Foo)
# admin.py:
class BarAdmin(admin.ModelAdmin):
list_filter = ('foo__name')
From documentation: Field names in list_filter can also span relations using the __ lookup
Well, the docs say that you can may use ForeignKey field types in list_filter:
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
An example:
# models.py:
class Foo(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return self.name
class Bar(models.Model):
name = models.CharField(max_length=255)
foo = models.ForeignKey(Foo)
# admin.py:
class BarAdmin(admin.ModelAdmin):
list_filter = ('foo')
If you want to filter by a field from the related model, there's a patch on the way to make this work (will probably be merged into 1.2 as it seems):
http://code.djangoproject.com/ticket/3400
solution from this page worked for me http://www.hoboes.com/Mimsy/hacks/fixing-django-124s-suspiciousoperation-filtering/
define
class SmarterModelAdmin(admin.ModelAdmin):
valid_lookups = ()
def lookup_allowed(self, lookup, *args, **kwargs):
if lookup.startswith(self.valid_lookups):
return True
return super(SmarterModelAdmin, self).lookup_allowed(lookup, *args, **kwargs)
then allow the lookup for certain foreign key field
class PageAdmin(SmarterModelAdmin):
valid_lookups = ('parent')
If you construct the URL for the changelist manually then Django has no problems following relationships. For example:
/admin/contact/contact/?participant__event=8
or
/admin/contact/contact/?participant__event__name__icontains=er
Both work fine (although the latter doesn't add 'distinct()' so might have duplicates but that won't usually be an issue for filters)
So you just need to add something to the page that creates the correct links. You can do this either with by overriding the changelist template or by writing a custom filterspec. There are several examples I found by Googling - particularly on Django Snippets
You can easily create custom filters since Django 1.4 by overriding django.contrib.admin.SimpleListFilter class.
More information :
Admin list_filter documentation ;
Django-1.4 release note.
I ran into the same problem and really needed a solution. I have a workaround that lets you create a filter on a FK related model property. You can even traverse more than one FK relationship. It creates a new FilterSpec subclass that subclasses the default RelatedFilterSpec used to give you a filter on a ForeignKey field.
See http://djangosnippets.org/snippets/2260/
The Haes answer works perfectly, but if the __ looks up to another ForeignKey field, you end up with a blank result. You must place another __ lookup, until it points to the real field.
In my case: list_filter = ('place__condo__name', )
my models.py:
class Condo(models.Model):
name = models.CharField(max_length=70)
...
class Place(models.Model):
condo = models.ForeignKey(Condo)
...
class Actions(models.Model):
place = models.ForeignKey(Place)
...