I have created a knowledge structure that has "blocks"and each block has children to cater for different situations.
The code is:
models.py
class KBSBlock(models.Model):
name = models.CharField(max_length=150, unique=True)
code = models.CharField(max_length=4, blank=True)
status=models.CharField(max_length=1, choices=Status_Choices, default='Draft')
enter_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT)
tags = TaggableManager(blank=True)
attribute1 = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if self.code is None or self.code == "":
self.code = create_code4(self)
super(KBSBlock, self).save(*args, **kwargs)
#receiver(post_save, sender=KBSBlock)
def create_block(sender, instance, created, **kwargs):
if created:
#create_block = BlockDetails.objects.create(block_dts=instance)
print('Working!')
class BlockDetails(models.Model):
block_dts = models.ForeignKey('KBSBlock', on_delete=models.CASCADE)
code = models.CharField(max_length=2, blank=True)
attribute1 = models.CharField(max_length=100, default='All')
created_at = models.DateTimeField(auto_now_add=True)
enter_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT)
status=models.CharField(max_length=1, choices=Status_Choices, default='Draft')
Whenever I create a block, I want to create a generic detail in BlockDetails for the block with (code='00', attribute1='All', enter_by='request.user')
It prints the 'working' bit with the 'create_block' line hashed out.
I am using PostgreSQL, Django 2.1 and Python 3.7, and cannot get it right.
Help Please
First of all thanks to #Dani Herrera and #Davit Tovmasyan! Between the two of them I figured out what the problem was: Turns out I had a few things wrong.
The error was coming from the database: value too long for type character varying(1) telling me that I was trying to enter a string that was too long for the intended field. This field was the status field - It appears that even though the choices option worked perfectly in normal circumstances, the signal command wanted the short form of the choice only.
The correct code is as follows:
#receiver(post_save, sender=KBSBlock)
def create_block(sender, instance, created, **kwargs):
if created:
instance.blockdetails_set.create(block_dts=instance.name, code='00', enter_by=instance.enter_by, attribute1='All', status='D')
NB: the case of the modelname MUST be lowercase, even in the model class has uppercase letters
Once I corrected that - everything worked.
Related
I am working on a school project using Django and Python.
Now I have created a website for using rest-apis. However, while testing I encountered an error that I simply can't seem to be able to solve. It occurs whenever I try to create a movie with POSTMAN using the api.I get the following error over and over again and I can't find what is wrong.
Error message:
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.__name__, kwarg))
TypeError: Movie() got an unexpected keyword argument 'actors'
My serializer
class MovieSerializer(serializers.ModelSerializer):
# Queryset gets all the data from the Actor model as specified with objects.all()
actor_pks = serializers.PrimaryKeyRelatedField(queryset=Actor.objects.all(), source='actors', write_only=True,
label='Actors', many=True)
rent_pks = serializers.PrimaryKeyRelatedField(source='rent', read_only=True, label='Rent')
# Change image-options to allow post/put/patch without an image
image = serializers.ImageField(allow_null=True, required=False)
def __init__(self, *args, **kwargs):
# Get additional parameters from constructor
depth = kwargs.pop('depth', None)
fields = kwargs.pop('fields', None)
# Add diffrent pks to fields if field is not None from constructor
fields.append('actor_pks') if fields is not None else None
fields.append('rent_pks') if fields is not None else None
fields.append('image') if fields is not None else None
# Overwrite meta tags
self.Meta.depth = depth if depth is not None else 1
self.Meta.fields = fields if fields is not None else '__all__'
# Call super-constructor
super(MovieSerializer, self).__init__(*args, **kwargs)
class Meta:
model = Movie
My Movie Model:
class Movie(models.Model):
"""
Movie-Model. Many-to-Many relation with Rent.
"""
title = models.CharField(null=False, max_length=50)
publishdate = models.CharField(null=False, max_length=20)
genre = models.CharField(null=True, max_length=50)
is_borrowed = models.BooleanField(null=False, default=False)
image = models.ImageField(null=False, upload_to='movies', default='noimage.png')
rent = models.ManyToManyField(Rent, blank=False)
actor = models.ForeignKey(Actor, null=False, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return '{}'.format(self.title)
def save(self, *args, **kwargs):
if not self.image:
if self.id:
self.image = Movie.objects.get(pk=self.id).image
else:
self.image = 'noimage.png'
super().save(*args, **kwargs)
I would be glad for any help with this problem. I have been working on it quite a while now and I am simply to dumb to find a solution for this.
Thanks for your help lads.
After a lot of time I was able to find the the answer to the question.
In the models in my Movie model, I had the following field implemented.
actor = models.ForeignKey(Actor, null=False, on_delete=models.CASCADE)
Turns out I had it's relation set wrong and therefor the serializer threw the error over and over again, since he was not able to make the connection, even if I changed the model field to "actors".
The solution was to turn the actor = models.ForeignKey to the following:
actor = models.ManyToManyField(Actor, related_name='movie_list', blank=False)
As well as change the actor_pks variable to the following:
actor_pks = serializers.PrimaryKeyRelatedField(queryset=Actor.objects.all(), source='actor', write_only=True, label='Actors', many=True)
There is an application model. The meaning of it is quite simple, the Author submits the application, the site administrator appoints the Contractor for its execution, which after completing the received application completes it. Everything seems to be fine, the application model was created, made sure that after the administrator chooses the Contractor the application immediately received the status of closed.
But here is one problem that I can not cope with when the Administrator closes the application (Status "Completed"), then the application does not acquire the status Completed, because the Artist is assigned to it because of the save function in the model.
How to make the status of the application complete, even if a contractor is appointed to this application? In advance I ask you to excuse me for such a presentation of the question, I'm still a beginner. Many thanks to all those who can help)
models.py
class Application(models.Model):
STATUS_CHOICES = (
('In_the_work', 'В работе'),
('New', 'Новая'),
('Complited', 'Завершена')
)
author = models.ForeignKey('auth.User', related_name = '+', verbose_name = 'Автор')
title = models.CharField(max_length=50, verbose_name = 'Заголовок')
text = models.TextField(verbose_name = 'Описание проблемы')
room = models.CharField(max_length = 4, verbose_name = 'Кабинет')
published_date = models.DateField(blank=True, null=True, default =
datetime.datetime.now, verbose_name = 'Дата')
status = models.CharField(max_length=15, choices=STATUS_CHOICES,
default='Новая', verbose_name = 'Статус')
owner = models.ForeignKey('auth.User', related_name = '+', null = True,
blank = True, limit_choices_to={ 'groups__name': 'Техническая поддержка'},
verbose_name = 'Исполнитель')
def save(self, *args, **kwargs):
if self.owner != None:
self.status = 'In_the_work'
super(Application, self).save(*args, **kwargs)
I am not sure about what you mean about an "Artist" being assigned to the application.
When you mean that a contractor is assigned to it, I am thinking you are referring to assigning an "owner" (owner field value) to the Application model. If that is the case, the error is that, in your save method you are checking for the owner being different than None, in which case you always overwrite the status to "In_the_work".
So maybe a solution would be something like:
def save(self, *args, **kwargs):
if self.status != 'Complited' and self.owner is not None:
self.status = 'In_the_work'
super(Application, self).save(*args, **kwargs)
In that way, you are only overwritting status if status is different than complited in the first place, not everytime the owner is not None.
Thank you.
My Career model has fields, since, until, and currently_employed.
# resume/models.py
...
class Career(models.Model):
resume = models.ForeignKey(Resume, on_delete=models.CASCADE)
since = models.DateField()
until = models.DateField(blank=True, null=True)
currently_employed = models.BooleanField()
company = models.CharField(max_length=50)
position = models.CharField(max_length=50)
achivement = models.TextField(default='')
I'd like to set until to current date if currently_employed is checked in the django(python) code, not in the template(html/js), as possible.
# resume/forms.py
...
class CareerForm(forms.ModelForm):
...
def clean(self):
cleaned_data = super().clean()
if cleaned_data['currently_employed'] == True:
cleaned_data['until'] = timezone.now().date()
# Check since < until
if cleaned_data['since'] >= cleaned_data['until']:
raise ValidationError('"Until" should be later than "Since"')
...
Is it OK to set the until nullable?(and its form field set required=False)
However, it would not be null in my logic since by currently employed, or user put that.
Keep the 'until' field as null in the database. If you set it to the current date then it's incorrect the following day as long as the user is still employed. You can still have a convenience which returns the current date if the user is still employed. This also means that the currently_employed database field becomes redundant.
class Career(models.Model):
...
_until = models.DateField(blank=True, null=True)
#property
def until(self):
return self._until or timezone.now().date()
#property
def currently_employed(self):
return self._until is None
I am completely new to django and was a php coder previously, so please bear with me if i am being dumb.
I have three models defined in my app, Comprehension, Question, Answer. Each comprehension has multiple questions and answers defined as 'inline' in the Comprehension model. Questions are input directly by the admin, but answers would added automatically from the comprehension.
What I want to achieve is, to split the comprehension in to sentences and add each sentence as an answer object with foreignkey of the current comprehension.
I am trying to override the save method in Comprehension model. But when I click save, it gives an instance error
Cannot assign "23L": "Answer.ComprehensionAnswer" must be a "Comprehension" instance.
How do I assign/create and instance here ? or am I following a wrong approach. If so, kindly guide me to the right approach.
Following are the contents of models.py
class Question(models.Model):
QuestionText = models.CharField(max_length=500, verbose_name='Question Text')
QuestionTypeID = models.ManyToManyField(QuestionType, verbose_name='Question Type')
ComprehensionQuestion = models.ForeignKey(Comprehension, verbose_name='comprehension')
QuestionRemarks = models.CharField(max_length=500, verbose_name='remarks', null=True, blank=True)
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.QuestionText
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
class Answer(models.Model):
AnswerText = models.CharField(max_length=500, verbose_name='Answer Text')
AnswerTypeID = models.ManyToManyField(AnswerType, verbose_name='Answer Type')
ComprehensionAnswer = models.ForeignKey(Comprehension, verbose_name='Comprehension', null=True, blank=True)
AnswerRemarks = models.CharField(max_length=500, verbose_name='Remarks')
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.AnswerText
class Comprehension(models.Model):
ComprehensionTitle = models.CharField(max_length=100, verbose_name='Comprehension Title')
ComprehensionsText = models.TextField(verbose_name='Text')
ComprehensionsRemarks = models.CharField(max_length=400, verbose_name='Remarks for this Comprehension', null=True, blank=True)
LastUpdate = models.DateTimeField("Last Updated", auto_now=True)
def __unicode__(self):
return self.ComprehensionTitle
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
def save(self, *args, **kwargs):
#overrides the default save function to split the comprehension paragraph into sentences and adds them as probable answers
AnswerList = self.ComprehensionsText.split("u'\u0964'")
for sentence in AnswerList:
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self.pk)
super(Comprehension, self).save(*args, **kwargs)
Content inside admin.py
class ComprehensionAdmin(admin.ModelAdmin):
form = ComprehensionForm
fieldsets = [
('Main', {'fields': ['ComprehensionTitle','ComprehensionsText']}),
('Additional Info', {'fields': ['ComprehensionsRemarks'], 'classes': ['collapse']}),
]
inlines = [QuestionInline, AnswerInline]
list_display = ('ComprehensionTitle', 'LastUpdate')
list_per_page = 10
class QuestionInline(admin.TabularInline):
model = Question
extra = 2
class AnswerInline(admin.TabularInline):
model = Answer
extra = 2
admin.site.register(Question)
admin.site.register(Answer)
admin.site.register(Comprehension, ComprehensionAdmin)
I have also followed the approach mentioned on this page. But, blank about how to create the objects in commit condition using the foreignkey of Comprehension model.
You should use self instead of self.pk and note that self refers the current object.
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self)
From the traceback, it clearly shows that, ComprehensionAnswer attribute of Answer model expects Comprehension model's object. But you're passing the id of that object.
I have Django version 1.4.5
Here are the relevant parts of my model
class Product (models.Model):
name=models.CharField(max_length=200)
description=models.TextField()
label=models.ForeignKey('Label')
pub_date = models.DateTimeField(editable=False)
def save(self):
#item will not have id if this is the first save
if not self.id:
self.pub_date = datetime.date.today()
super(Product, self).save()
def __unicode__(self):
return self.name
class Label(models.Model):
"""
A clothing label, e.g. Kate Spade
"""
name=models.CharField(max_length=100)
def __unicode__(self):
return self.name
When I attempt to publish a Product, selecting a Label works fine. Publishing the item works as expected, and the label field remains populated upon returning to the Product in the admin console. However, if I attempt to change the value of the label field, I am taken to the default list of Products page, with the message "he product "Prod 1" was changed successfully" but returning to the Prod 1 page reveals that the field wasn't actually saved properly.
Any ideas here?
super(Product, self).save() is within the if block, so it isn't being called on edits. Also, why not just use auto_now_add on the pub_date field?
In your case, no need to set the date & time explicitly. You can use 'auto_now_add' Please fer this link for more details.
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField.auto_now_add
class Product (models.Model):
name=models.CharField(max_length=200)
description=models.TextField()
label=models.ForeignKey('Label')
pub_date = models.DateTimeField(editable=False, auto_now_add = True)
def __unicode__(self):
return self.name
If you need to set it manually, Use the following snippet. It calls super class for change also.
def save(self):
#item will not have id if this is the first save
if not self.id:
self.pub_date = datetime.date.today()
super(Product, self).save()