here is the model
class CoursePage(Page):
"""docstring for Course"""
name=RichTextField(null=False)
categories = ParentalManyToManyField('it.ItCourseCategory', blank=True)
description=StreamField([
('heading', blocks.CharBlock()),
('paragraph', blocks.RichTextBlock()),
('image', ImageChooserBlock()),
])
icon= models.ForeignKey(
'wagtailimages.Image', null=True, blank=True,
on_delete=models.SET_NULL, related_name='+'
)
def __init__(self, arg):
super(Course, self).__init__()
self.arg = name
content_panels=Page.content_panels + [
FieldPanel('name'),
StreamFieldPanel('description'),
ImageChooserPanel('icon'),
FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
]
I got this
TypeError at /admin/pages/add/it/coursepage/10/
init() got an unexpected keyword argument 'owner'
You should leave out the __init__ method.
It looks like you're trying to provide a way to pass the name field when creating a page, but Django already provides this capability on models such as Page:
my_course_page = CoursePage(name='<p>My course name</p>')
(See the Django tutorial for further examples.) If you choose to override the __init__ method, you need to define it to accept all arguments and keyword arguments, and pass them on to super, so that this built-in behaviour doesn't break:
def __init__(self, *args, **kwargs):
super(CoursePage, self).__init__(*args, **kwargs)
# add your own code here
However, in this case you don't need the __init__ method at all.
Related
I have a Django+Wagtail blog site integrated with django_comments_xtd as below:
class PostDetail(Page):
...
class Comment(XtdComment):
page = models.ForeignKey('PostDetail', on_delete=models.CASCADE)
def save(self, *args, **kwargs):
if self.user:
self.user_name = self.user.username
self.page = PostDetail.objects.get(pk=self.object_pk)
super(Comment, self).save(*args, **kwargs)
Now I am about to create another class model class SurveyPoll(Page):,
How can I apply the same Comment to the newly-created model? Should I create another comment model ?
You have many options for that, simplist and cleanest is to inherit from both (Page, Comment)
I have a model.
class Exam(models.Model):
Examname = models.CharField(null=False, blank=False, max_length=255)
def save(self, *args, **kwargs):
self.Examname = self.Examname.lower()
return super(Exam, self).save(*args, **kwargs)
class Meta:
unique_together = ["Examname"]
def __str__(self):
return self.Examname
Examname must be case insensitive in order to avoid the duplicate data. I converted all to small letters and stored. But it is not detecting the duplicate data. for example if i insert External as Examname it is storing as external but other name if i give as external then only it detects as dulicate data. External or eXternal or any atleast one capital letter is there it is not detecting as duplicate data but stored as small letters
First of all, if regno should store numbers as well as characters, do not use FloatField but for example CharField
If you want avoid case sensitivity issues, you may want for example decide to always store values low case when saving your object as follow:
def save(self, *args, **kwargs):
self.regno = self.regno.lower()
super(Show, self).save(*args, **kwargs)
If you need to preserve case, the alternative option would be to duplicate lowcase content in a secondary CharField. Which can be automated in the save method.
If you try to insert a duplicate value, django will throw an IntegrityError, which should be handled.
class MyModel(models.Model):
mytextfield = models.CharField()
lowcase_textfield = models.CharField(unique=True)
def save(self, *args, **kwargs):
self.lowcase_textfield = self.mytextfield.lower()
try:
super(MyModel, self).save(*args, **kwargs)
except IntegrityError as e:
# INSERT YOUR EXCEPTION HANDLING HERE
pass
Hi I am trying to add a foreign key to one of my model classes. For some reason this key in particular causes an exception when used in this specific class. I can use it as a foreign key in a another one of my classes and it works fine.
I am running django 1.6.1 against MSSQL Server 12.
Here's the stack trace.
Environment:
Request Method: GET
Request URL: `http://somehost:8000/admin/tracker/engagement/`
Django Version: 1.6.1
Python Version: 2.7.5
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tracker')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware')
Traceback:
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python27\lib\site-packages\django\contrib\admin\options.py" in wrapper
432. return self.admin_site.admin_view(view)(*args, **kwargs)
File "C:\Python27\lib\site-packages\django\utils\decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
52. response = view_func(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\contrib\admin\sites.py" in inner
198. return view(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\utils\decorators.py" in _wrapper
29. return bound_func(*args, **kwargs)
File "C:\Python27\lib\site-packages\django\utils\decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\utils\decorators.py" in bound_func
25. return func(self, *args2, **kwargs2)
File "C:\Python27\lib\site-packages\django\contrib\admin\options.py" in changelist_view
1411. 'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
File "C:\Python27\lib\site-packages\django\db\models\query.py" in __len__
77. self._fetch_all()
File "C:\Python27\lib\site-packages\django\db\models\query.py" in _fetch_all
854. self._result_cache = list(self.iterator())
File "C:\Python27\lib\site-packages\django\db\models\query.py" in iterator
220. for row in compiler.results_iter():
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py" in results_iter
710. for rows in self.execute_sql(MULTI):
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
781. cursor.execute(sql, params)
File "C:\Python27\lib\site-packages\django\db\backends\util.py" in execute
69. return super(CursorDebugWrapper, self).execute(sql, params)
File "C:\Python27\lib\site-packages\django\db\backends\util.py" in execute
53. return self.cursor.execute(sql, params)
File "C:\Python27\lib\site-packages\django\db\utils.py" in __exit__
99. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "C:\Python27\lib\site-packages\django\db\backends\util.py" in execute
53. return self.cursor.execute(sql, params)
File "C:\Python27\lib\site-packages\sql_server\pyodbc\base.py" in execute
432. return self.cursor.execute(sql, params)
Exception Type: ProgrammingError at /admin/tracker/engagement/
Exception Value: ('42S22', "[42S22] [Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid column name 'STATE'. (207) (SQLExecDirectW)")
Here's the model
class EngTxn(models.Model):
eng = models.ForeignKey('Engagement', db_column='ENG_ID') # Field name made lowercase.
date = models.DateField(db_column='DATE', blank=True, null=True, default=date.today) # Field name made lowercase.
engagement_state = models.ForeignKey('EngagementState', db_column='STATE', blank=True, null=True) # Field name made lowercase.
comment = models.CharField(db_column='COMMENT', max_length=255, blank=True) # Field name made lowercase.
follow_up = models.DateField(db_column='FOLLOW_UP', blank=True, null=True) # Field name made lowercase.
id = models.AutoField(db_column='ID', primary_key=True) # Field name made lowercase.
class Meta:
managed = True
db_table = 'Eng_txn'
def __unicode__(self): # Python 3: def __str__(self):
return self.eng_state
class Engagement(models.Model):
account_name = models.ForeignKey(Account, db_column='S_NAME') # Field name made lowercase.
ibm_contact_id = models.CharField(db_column='IBM_CONTACT_ID', max_length=255, blank=True) # Field name made lowercase.
cust_contact = models.CharField(db_column='CUST_CONTACT', max_length=255, blank=True) # Field name made lowercase.
engagment_state = models.ForeignKey('EngagementState', db_column='STATE', blank=True, null=True) # Field name made lowercase.
start_date = models.DateField(db_column='START_DATE', blank=True, null=True, default=date.today) # Field name made lowercase.
planned_enddate = models.DateField(db_column='PLANNED_ENDDATE', blank=True, null=True, default=date.today) # Field name made lowercase.
actual_enddate = models.DateField(db_column='ACTUAL_ENDDATE', blank=True, null=True, default=date.today) # Field name made lowercase.
prime_id = models.CharField(db_column='PRIME_ID', max_length=255, blank=True) # Field name made lowercase.
backup_id = models.CharField(db_column='BACKUP_ID', max_length=255, blank=True) # Field name made lowercase.
sponsor_id = models.CharField(db_column='SPONSOR_ID', max_length=255, blank=True) # Field name made lowercase.
support_contact = models.CharField(db_column='SUPPORT_CONTACT', max_length=255, blank=True) # Field name made lowercase.
justification = models.CharField(db_column='JUSTIFICATION', max_length=255, blank=True) # Field name made lowercase.
eng_type = models.CharField(db_column='ENG_TYPE', max_length=255, blank=True) # Field name made lowercase.
app_id = models.CharField(db_column='APP_ID', max_length=255, blank=True) # Field name made lowercase.
chklist_blob = models.CharField(db_column='CHKLIST_BLOB', max_length=255, blank=True) # Field name made lowercase.
eng_id = models.AutoField(db_column='ENG_ID', primary_key=True) # Field name made lowercase.
icn = models.SmallIntegerField(db_column='ICN', blank=True, null=True) # Field name made lowercase.
acct_type = models.ForeignKey(Accounttype, db_column='ACCT_TYPE_ID', blank=True, null=True)
class Meta:
managed = True
db_table = 'Engagement'
def __unicode__(self): # Python 3: def __str__(self):
return str(self.account_name)
class EngagementState(models.Model):
eng_state_id = models.SmallIntegerField(db_column='ENG_STATE_ID', primary_key=True) # Field name made lowercase.
eng_state = models.CharField(db_column='STATE', max_length=50) # Field name made lowercase.
class Meta:
managed = True
db_table = 'EngagementState'
def __unicode__(self): # Python 3: def __str__(self):
return self.eng_state
class CuspTransaction(models.Model):
s_name = models.ForeignKey(Account, db_column='S_NAME') # Field name made lowercase.
txn_date = models.DateField(db_column='TXN_ENDDATE', blank=True, null=True, default=date.today)# Field name made lowercase.
engagement_state = models.ForeignKey('EngagementState', db_column='STATE', blank=True, null=True) # Field name made lowercase.
def __unicode__(self): # Python 3: def __str__(self):
return str(self.s_name)
When I try and access the Engagement table from the Django admin, I get the error specified about, it complains about 'STATE' not being a valid column. If I access the CuspTransaction table in the django admin, it works fine and they are referencing the same foreign key. I am brand new to Django and I have no idea what's going on here. The column obviously exists and it's accessible since it works from CuspTransaction. Any thoughts?
I initially did an inspect to create a model from an existing schema, I think the error I was getting had something to do with that. Today I cleaned up the model and and worked the other way creating the database from the schema. Everything seems to be working fine now.
When I got this error, it is usually because I made changes to model field but forgot to makemigrations and migrate
I have a users share model something like below:
class Share( models.Model ):
sharer = models.ForeignKey(User, verbose_name=_("Sharer"), related_name='sharer')
receiver = models.ForeignKey(User, verbose_name=_("Receiver"), related_name='receiver')
class Meta:
unique_together = ( ("sharer", "receiver"), ("receiver", "sharer") )
I want to save a single object for sharer(S) and receiver(R) (order doesn't matters R-S or S-R). but above unique_together will not fulfil this; Suppose R-S is in database and then if I save S-R I will not get validation for this. For this I have written custom unique validation for Share model.
def validate_unique(
self, *args, **kwargs):
super(Share, self).validate_unique(*args, **kwargs)
if self.__class__.objects.filter( Q(sharer=self.receiver, receiver=self.sharer) ).exists():
raise ValidationError(
{
NON_FIELD_ERRORS:
('Share with same sharer and receiver already exists.',)
}
)
def save(self, *args, **kwargs):
# custom unique validate
self.validate_unique()
super(Share, self).save(*args, **kwargs)
This method works fine in normal use.
Problem:
I have an matching algorithm which gets a share's and a receiver's requests and saves Share object(either S-R or R-S) then send them response(share object) at almost same time. As I am checking duplication with query(no database level) it takes time, so at the end I have 2 Objects S-R and R-S.
I want some solution for this that for a sharer S and a receiver R I can only save single share object, either S-R or R-S else get some validation error(like IntegrityError of databse).
Django=1.4, Database=Postgresql
You probably could solve this with postgresql's indexes on expressions but here is another way:
class Share( models.Model ):
sharer = models.ForeignKey(User)
receiver = models.ForeignKey(User), related_name='receiver')
key = models.CharField(max_length=64, unique=True)
def save(self, *args, **kwargs):
self.key = "{}.{}".format(*sorted([self.sharer_id, self.receiver_id]))
super(Share, self).save(*args, **kwargs)
But it obviously wouldn't work if you change values with QuerySet.update method. You also could look at django-denorm, it solves this with triggers.
Suppose my models.py is like so:
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
I want only one of my Character instances to have is_the_chosen_one == True and all others to have is_the_chosen_one == False . How can I best ensure this uniqueness constraint is respected?
Top marks to answers that take into account the importance of respecting the constraint at the database, model and (admin) form levels!
Whenever I've needed to accomplish this task, what I've done is override the save method for the model and have it check if any other model has the flag already set (and turn it off).
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def save(self, *args, **kwargs):
if self.is_the_chosen_one:
try:
temp = Character.objects.get(is_the_chosen_one=True)
if self != temp:
temp.is_the_chosen_one = False
temp.save()
except Character.DoesNotExist:
pass
super(Character, self).save(*args, **kwargs)
I'd override the save method of the model and if you've set the boolean to True, make sure all others are set to False.
from django.db import transaction
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def save(self, *args, **kwargs):
if not self.is_the_chosen_one:
return super(Character, self).save(*args, **kwargs)
with transaction.atomic():
Character.objects.filter(
is_the_chosen_one=True).update(is_the_chosen_one=False)
return super(Character, self).save(*args, **kwargs)
I tried editing the similar answer by Adam, but it was rejected for changing too much of the original answer. This way is more succinct and efficient as the checking of other entries is done in a single query.
It is simpler to add this kind of constraint to your model
after Django version 2.2. You can directly use UniqueConstraint.condition. Django Docs
Just override your models class Meta like this:
class Meta:
constraints = [
UniqueConstraint(fields=['is_the_chosen_one'], condition=Q(is_the_chosen_one=True), name='unique_is_the_chosen_one')
]
Instead of using custom model cleaning/saving, I created a custom field overriding the pre_save method on django.db.models.BooleanField. Instead of raising an error if another field was True, I made all other fields False if it was True. Also instead of raising an error if the field was False and no other field was True, I saved it the field as True
fields.py
from django.db.models import BooleanField
class UniqueBooleanField(BooleanField):
def pre_save(self, model_instance, add):
objects = model_instance.__class__.objects
# If True then set all others as False
if getattr(model_instance, self.attname):
objects.update(**{self.attname: False})
# If no true object exists that isnt saved model, save as True
elif not objects.exclude(id=model_instance.id)\
.filter(**{self.attname: True}):
return True
return getattr(model_instance, self.attname)
# To use with South
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^project\.apps\.fields\.UniqueBooleanField"])
models.py
from django.db import models
from project.apps.fields import UniqueBooleanField
class UniqueBooleanModel(models.Model):
unique_boolean = UniqueBooleanField()
def __unicode__(self):
return str(self.unique_boolean)
Trying to make ends meet with the answers here, I find that some of them address the same issue successfully and each one is suitable in different situations:
I would choose:
#semente: Respects the constraint at the database, model and admin form levels while it overrides Django ORM the least possible. Moreover it can be used inside a through table of a ManyToManyField in aunique_together situation.
class MyModel(models.Model):
is_the_chosen_one = models.BooleanField(null=True, default=None, unique=True)
def save(self, *args, **kwargs):
if self.is_the_chosen_one is False:
self.is_the_chosen_one = None
super(MyModel, self).save(*args, **kwargs)
Update: NullBooleanField will be deprecated by Django-4.0, for BooleanField(null=True).
#Ellis Percival: Hits the database only one extra time and accepts the current entry as the chosen one. Clean and elegant.
from django.db import transaction
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def save(self, *args, **kwargs):
if not self.is_the_chosen_one:
# The use of return is explained in the comments
return super(Character, self).save(*args, **kwargs)
with transaction.atomic():
Character.objects.filter(
is_the_chosen_one=True).update(is_the_chosen_one=False)
# The use of return is explained in the comments
return super(Character, self).save(*args, **kwargs)
Other solutions not suitable for my case but viable:
#nemocorp is overriding the clean method to perform a validation. However, it does not report back which model is "the one" and this is not user friendly. Despite that, it is a very nice approach especially if someone does not intend to be as aggressive as #Flyte.
#saul.shanabrook and #Thierry J. would create a custom field which would either change any other "is_the_one" entry to False or raise a ValidationError. I am just reluctant to impement new features to my Django installation unless it is absoletuly necessary.
#daigorocub: Uses Django signals. I find it a unique approach and gives a hint of how to use Django Signals. However I am not sure whether this is a -strictly speaking- "proper" use of signals since I cannot consider this procedure as part of a "decoupled application".
The following solution is a little bit ugly but might work:
class MyModel(models.Model):
is_the_chosen_one = models.NullBooleanField(default=None, unique=True)
def save(self, *args, **kwargs):
if self.is_the_chosen_one is False:
self.is_the_chosen_one = None
super(MyModel, self).save(*args, **kwargs)
If you set is_the_chosen_one to False or None it will be always NULL. You can have NULL as much as you want, but you can only have one True.
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def save(self, *args, **kwargs):
if self.is_the_chosen_one:
qs = Character.objects.filter(is_the_chosen_one=True)
if self.pk:
qs = qs.exclude(pk=self.pk)
if qs.count() != 0:
# choose ONE of the next two lines
self.is_the_chosen_one = False # keep the existing "chosen one"
#qs.update(is_the_chosen_one=False) # make this obj "the chosen one"
super(Character, self).save(*args, **kwargs)
class CharacterForm(forms.ModelForm):
class Meta:
model = Character
# if you want to use the new obj as the chosen one and remove others, then
# be sure to use the second line in the model save() above and DO NOT USE
# the following clean method
def clean_is_the_chosen_one(self):
chosen = self.cleaned_data.get('is_the_chosen_one')
if chosen:
qs = Character.objects.filter(is_the_chosen_one=True)
if self.instance.pk:
qs = qs.exclude(pk=self.instance.pk)
if qs.count() != 0:
raise forms.ValidationError("A Chosen One already exists! You will pay for your insolence!")
return chosen
You can use the above form for admin as well, just use
class CharacterAdmin(admin.ModelAdmin):
form = CharacterForm
admin.site.register(Character, CharacterAdmin)
And that's all.
def save(self, *args, **kwargs):
if self.default_dp:
DownloadPageOrder.objects.all().update(**{'default_dp': False})
super(DownloadPageOrder, self).save(*args, **kwargs)
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def clean(self):
from django.core.exceptions import ValidationError
c = Character.objects.filter(is_the_chosen_one__exact=True)
if c and self.is_the_chosen:
raise ValidationError("The chosen one is already here! Too late")
Doing this made the validation available in the basic admin form
Using a similar approach as Saul, but slightly different purpose:
class TrueUniqueBooleanField(BooleanField):
def __init__(self, unique_for=None, *args, **kwargs):
self.unique_for = unique_for
super(BooleanField, self).__init__(*args, **kwargs)
def pre_save(self, model_instance, add):
value = super(TrueUniqueBooleanField, self).pre_save(model_instance, add)
objects = model_instance.__class__.objects
if self.unique_for:
objects = objects.filter(**{self.unique_for: getattr(model_instance, self.unique_for)})
if value and objects.exclude(id=model_instance.id).filter(**{self.attname: True}):
msg = 'Only one instance of {} can have its field {} set to True'.format(model_instance.__class__, self.attname)
if self.unique_for:
msg += ' for each different {}'.format(self.unique_for)
raise ValidationError(msg)
return value
This implementation will raise a ValidationError when attempting to save another record with a value of True.
Also, I have added the unique_for argument which can be set to any other field in the model, to check true-uniqueness only for records with the same value, such as:
class Phone(models.Model):
user = models.ForeignKey(User)
main = TrueUniqueBooleanField(unique_for='user', default=False)
Do I get points for answering my question?
problem was it was finding itself in the loop, fixed by:
# is this the testimonial image, if so, unselect other images
if self.testimonial_image is True:
others = Photograph.objects.filter(project=self.project).filter(testimonial_image=True)
pdb.set_trace()
for o in others:
if o != self: ### important line
o.testimonial_image = False
o.save()
I tried some of these solutions, and ended up with another one, just for the sake of code shortness (don't have to override forms or save method).
For this to work, the field can't be unique in it's definition but the signal makes sure that happens.
# making default_number True unique
#receiver(post_save, sender=Character)
def unique_is_the_chosen_one(sender, instance, **kwargs):
if instance.is_the_chosen_one:
Character.objects.all().exclude(pk=instance.pk).update(is_the_chosen_one=False)
2020 update to make things less complicated for beginners:
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField(blank=False, null=False, default=False)
def save(self):
if self.is_the_chosen_one == True:
items = Character.objects.filter(is_the_chosen_one = True)
for x in items:
x.is_the_chosen_one = False
x.save()
super().save()
Of course, if you want the unique boolean to be False, you would just swap every instance of True with False and vice versa.
When implementing a solution which overwrites model.save()*, I ran into the issue of Django Admin raising an error before hitting model.save(). The cause seems to be Admin calling model.clean() (or perhaps model.full_clean(), I didn't investigate too carefully) before calling model.save(). model.clean() in turn calls model.validate_unique() which raises a ValidationError before my custom save method can take care of the unique violation. To solve this I overwrote model.validate_unique() as follows:
def validate_unique(self, exclude=None):
try:
super().validate_unique(exclude=exclude)
except ValidationError as e:
validation_errors = e.error_dict
try:
list_validation_errors = validation_errors["is_the_chosen_one"]
for validation_error in list_validation_errors:
if validation_error.code == "unique":
list_validation_errors.remove(validation_error)
if not list_validation_errors:
validation_errors.pop(key)
except KeyError:
continue
if e.error_dict:
raise e
* the same would be true for a signal solution using pre_save, as pre_save is also not sent before .validate_unique is called