Author page in django migrations and questions - django

I want to make a website for eBooks with a page that has all the books published by one of the authors. The problem is that I have no idea how to do that. I will mention that I am a beginner.
I tried this int the model file
class Author(models.Model):
author = models.TextField()
class Product(models.Model):
…
author=models.ForeignKey(Author,on_delete=models.CASCADE)
The result in the terminal was:
File "/home/user/petnet/petnet-env/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 264, in check_constraints
raise IntegrityError(
django.db.utils.IntegrityError: The row in table 'store_product' with primary key '2' has an invalid foreign key: store_product.author_id contains a value 'anonim' that does not have a corresponding value in store_author.id.
I think this is caused by the act that I made the author field later and there were already authors fields from before, but then, when I tried to revert back to what I had before doing this, I got some errors regarding migrations.
Also the views were:
def author_detail(request, slug):
author = get_object_or_404(Author, slug=slug)
products = author.products.filter(status=Product.ACTIVE)
return render(request, 'store/author_detail.html', {
'author':author,
'products':products
})
But I am also curious if there is a chance I could use only this for models so I could use the form for adding a product in a much easier way.
class Product(models.Model):
DRAFT = 'draft'
WAITING_APPROVAL = 'waitingapproval'
ACTIVE = 'active'
DELETED = 'deleted'
STATUS_CHOICES = (
(DRAFT, 'Ciorna'),
(WAITING_APPROVAL, 'Asteapta aprobare'),
(ACTIVE, 'Activ'),
(DELETED, 'Sters')
)
user = models.ForeignKey(User, related_name='products',on_delete=models.CASCADE)
category=models.ForeignKey(Category, related_name='products',on_delete=models.CASCADE)
title = models.CharField(max_length=50)
image = models.ImageField(upload_to='uploads/product_images/', blank=True, null=True)
editie = models.IntegerField()
editura = models.CharField(max_length=50)
description = models.TextField(blank=True)
author = models.TextField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=50)
status = models.CharField(max_length=50, choices=STATUS_CHOICES, default=ACTIVE)

Related

Django Choices Not Being DIsplayed

Good day,
I am trying to create a django model that contains a choice whether the user has read or not read a book. For that I have made a choice list. But i am unable to display it on the admin panel. All other fields are getting displayed other than the choice field.
Can you please tell me where I am going wrong. I am new to django and have referred from the documnetation.
Following is the code:
class Book(models.Model):
YES = 'y'
NO = 'n'
DID_READ_CHOICES = [
(YES,'Yes'),
(NO,'No'),
]
title = models.CharField(max_length=100)
author = models.ForeignKey(
Author,
on_delete=models.SET_NULL,
null=True,
related_name='author_books'
)
genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book',blank=True,null=True)
read = models.CharField(
max_length=1,
choices=DID_READ_CHOICES,
default=NO,
),
objects = BookManager()
class Meta:
ordering = ['title']
def __str__(self):
return self.title
Thank you
There is a trailing question at the end of read, thus django did not detect the field.

I am working with Django, During inserting data into database i caught such error

I'm working with django, during inserting data into tables the error is generates as given below...
Error:
int() argument must be a string, a bytes-like object or a number, not 'Tbl_rule_category', How can we solve such error?
view.py
dataToRuleCtgry = Tbl_rule_category(category=category, created_by="XYZ",created_date=datetime.date.today())
dataToRuleCtgry.save()
dataToRule = Tbl_rule(rule_name=rule_name, closure=closure,category_id=Tbl_rule_category.objects.latest('category_id'), created_by="XYZ",created_date=datetime.date.today(), updated_by="XYZ", updated_date=datetime.date.today(), rule_type=rule_type, fk_tbl_rule_tbl_rule_category_id=Tbl_rule_category.objects.latest('category_id'))
dataToRule.save()
models.py
class Tbl_rule_category(models.Model):
category_id = models.AutoField(primary_key=True)
category = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
def __str__(self):
pass # return self.category, self.created_by
class Tbl_rule(models.Model):
rule_id = models.AutoField(primary_key=True)
rule_name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
category_id = models.IntegerField()
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
fk_tbl_rule_tbl_rule_category_id = models.ForeignKey(Tbl_rule_category,on_delete=models.CASCADE, related_name='fk_tbl_rule_tbl_rule_category_id_r')
def __str__(self):
return self.rule_name, self.closure, self.created_by, self.updated_by, self.rule_type
The error is occurring because the following is trying to add an object into an integer field: category_id=Tbl_rule_category.objects.latest('category_id')
You could just add: category_id=dataToRuleCtgry.get('category_id') or category_id=dataToRuleCtgry.category_id which will solve the error.
You also don't need to add: created_date=datetime.date.today() because your model defines auto_now=true.
As mentioned you should also amend the def __str__(self): to return a string.
https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.str
Alternatively
You could just add the object link directly to your foreign key for the category model.fk_tbl_rule_tbl_rule_category_id=dataToRuleCtgry. You would no longer need the integer field category_id.
It would be better practice to use the model field name category_id instead of fk_tbl_rule_tbl_rule_category_id. This would mean deleting category_id and then rename fk_tbl_rule_tbl_rule_category_id to category_id.
In Django, the ORM takes care of the basic database details for you; which means in your code you really don't have to worry about individual row ids for maintaining foreign key relationships.
In fact, Django automatically assigns primary keys to all your objects so you should concentrate on fields that are relevant to your application.
You also don't have to worry about naming fields in the database, again Django will take care of that for you - you should create objects that have fields that are meaningful to users (that includes you as a programmer of the system) and not designed for databases.
Each Django model class represents a object in your system. So you should name the classes as you would name the objects. User and not tbl_user. The best practice is to use singular names. Django already knows how to create plural names, so if you create a model class User, django will automatically display Users wherever it makes sense. You can, of course, customize this behavior.
Here is how you should create your models (we will define __str__ later):
class RuleCategory(models.Model):
name = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
class Rule(models.Model):
name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
category = models.ForeignKey(RuleCategory,on_delete=models.CASCADE)
Django will automatically create any primary or foreign key fields, and any intermediary tables required to manage the relationship between the two models.
Now, to add some records:
new_category = RuleCategory(name='My Category', created_by='XYZ')
new_category.save()
# Another way to set values
new_rule = Rule()
new_rule.name = 'Sample Rule'
new_rule.closure = closure
new_rule.created_by = 'XYZ'
new_rule.updated_by = 'XYZ'
new_rule.rule_type = rule_type
new_rule.category = new_category
new_rule.save()
Note this line new_rule.category = new_category - this is how we link two objects. Django knows that the primary key should go in the table and will take care of that automatically.
The final item is customizing the models by creating your own __str__ method - this should return some meaningful string that is meant for humans.
class RuleCategory(models.Model):
name = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
def __str__(self):
return '{}'.format(self.name)
class Rule(models.Model):
name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
category = models.ForeignKey(RuleCategory,on_delete=models.CASCADE)
def __str__(self):
return '{} for category {}'.format(self.name, self.category)
If you notice something, I just put self.category in the __str__ for the Rule model. This is because we have already defined a __str__ for the RuleCategory model, which just returns the category name; so now when we print our Rule we created, we will get Sample Rule for category My Category as a result.

Django generic foreign key reverse filter

I have a model called "Comments" which uses a generic foreign key:
class CommentManager(models.Manager):
def for_model(self, model):
"""
QuerySet for all comments for a particular model (either an instance or
a class).
"""
ct = ContentType.objects.get_for_model(model)
qs = self.get_query_set().filter(content_type=ct)
if isinstance(model, models.Model):
qs = qs.filter(object_pk=force_text(model._get_pk_val()))
return qs
class Comment(models.Model):
"""
A user comment about some object.
"""
status = models.CharField(max_length=12, blank=True, null=True)
sub_status = models.CharField(max_length=500, blank=True, null=True)
comment = models.TextField()
content_type = models.ForeignKey(
ContentType,
verbose_name=_('content type'),
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField(_('object ID'))
content_object = generic.GenericForeignKey(ct_field="content_type",
fk_field="object_pk")
One of the things you can put comments on are Tickets:
class Ticket(CommonModel):
type = models.ForeignKey(TicketType)
priority = models.PositiveSmallIntegerField()
status = models.ForeignKey(TicketStatus)
access_serial_number = models.PositiveSmallIntegerField(null=True)
parent = models.ForeignKey('self', null=True, related_name='child')
submitted = models.DateTimeField()
I do a lot of filtering of Tickets - in the past all I did with Comments on Tickets is that when I displayed a Ticket, I used Comments.objects.for_model(ticket) to find all the Comments for it. But now what I want to do is find Tickets that have a specific text in the comment. There is no comment_set or equivalent with GenericForeignKey.
This is what I've come up with, but it's pretty horrible:
comment_ticket_ids = [int(c.object_pk) for c in Comment.objects.for_model(Ticket).filter(comment__icontains='error')]
tickets = Ticket.filter(status=open_status, id__in=comment_ticket_ids)
There must be a better way.
Perhaps you could add something using .extra() to help. Instead of
comment_ticket_ids = [int(c.object_pk) for c in Comment.objects.for_model(Ticket).filter(comment__icontains='error')]
tickets = Ticket.filter(status=open_status, id__in=comment_ticket_ids)
You could attach the field id_wanted:
extra_select = {
'id_wanted': 'CASE WHEN (SELECT COUNT(*) FROM tickets WHERE comments something) > 0 THEN TRUE ELSE FALSE END'
}
Then filter for tickets with the extra select:
tickets = Tickets.objects.filter(ticket__status=open_status, id_wanted__isnull=False).extra(extra_select)
It's not fully clear to me why you can't have a FKey relationship between these two models.

Django admin says SuspiciousOperation, filtering not allowed

I have 3 related models in my system. Each user belongs to a particular place. Users can send messages, and comment on messages, kind of like forum threads.
Here are the 3 models:
class Place(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
class Message(models.Model):
creator = models.ForeignKey(User)
title = models.CharField(max_length=40)
content = models.CharField(max_length=3000)
date_created = models.DateTimeField(default=timezone.now)
place = models.ForeignKey(Place)
class Comment(models.Model):
creator = models.ForeignKey(User)
content = models.CharField(max_length=3000)
date_created = models.DateTimeField(default=timezone.now)
message = models.ForeignKey(Message)
I want this structure to be reflected in my AdminModels. So for my PlaceAdmin I wrote this:
class PlaceAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'list_messages')
def list_messages(self, obj):
url = reverse('admin:user_content_message_changelist')
return 'List messages'.format(url, obj.id)
list_messages.allow_tags = True
list_messages.short_description = 'Messages'
This works perfectly, each place links to a list of messages filtered by that place. So I did the same for my MessageAdmin:
class MessageAdmin(admin.ModelAdmin):
list_display = ('title', 'list_comments')
def list_comments(self, obj):
url = reverse('admin:user_content_comment_changelist')
return 'List comments'.format(url, obj.id)
list_comments.allow_tags = True
list_comments.short_description = 'Comments'
And I get the following error:
SuspiciousOperation at /admin/user_content/comment/
Filtering by message__id__exact not allowed
I don't understand why one is allowed and the other isn't. Any ideas? I'm using Django 1.5.
I realised I made a mistake - the code I showed here was simplified, and the Message model actually inherits from an abstract Content model, so I needed the URL for the comment list to be:
List comments

How does one do a model query from other model function?

I have the following classes: Student, LabJournal, JournalResponse, and JournalField. I want to define a "status" function for student to determine how many questions (JournalField) they've answered (JournalResponse). The problem is the function dies without a return on the following line:
total_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).count()
My guess is that I'm doing the model query wrong from within the class definition, or that you're not allowed to query from within a separate model. However I have not found anything in the docs to confirm or deny this, and without any errors it's difficult to debug. Running Django 1.1.
Code below:
class Student (models.Model):
user = models.ForeignKey(User, unique=True, null=False, related_name='student')
teacher = models.ForeignKey(User, null=False, related_name='students')
assignment = models.ForeignKey(LabJournal, blank=True, null=True, related_name='students')
def get_absolute_url(self):
return "/labjournal/student/%i/" % self.id
def status(self):
if self.assignment == None : return "unassigned"
percent_done = 0
total_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).count()
answered_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).filter(text!=None).count()
percent_done = (answered_questions/total_questions)*100
return '%d%% done' % percent_done
class JournalResponse (models.Model):
owner = models.ForeignKey(Student, null=False, related_name='responses')
field = models.ForeignKey(JournalField, null=False, related_name='responses')
text = models.TextField(null=True, blank=True)
file = models.URLField(null=True, blank=True)
class JournalField (models.Model):
TYPE_CHOICES = (
(u'HTML', u'HTML'),
(u'IF', u'ImageField'),
(u'TF', u'TextField'),
)
journal = models.ForeignKey(LabJournal, null=False, related_name='fields', help_text='Parent Journal')
ordinal = models.IntegerField(help_text='Field order')
type = models.CharField(null=False, max_length=64, choices=TYPE_CHOICES, help_text='Field type')
# Contains HTML content for HTML fields, contains the text marked "question" closest
# to and above the current field for picture and text entry fields
content = models.TextField(help_text='Should contain HTML content for HTML (question) fields or associated (previous question) HTML for ImageFields and TextFields.')
UPDATED
Here's the working status method:
def status(self):
if self.assignment == None : return "unassigned"
percent_done = 0
# sets up query, but doesn't actually hit database
response_set = self.responses.filter(owner=self).filter(field__journal=self.assignment)
# force float so divide returns float
# the two count statements are the only two actual hits on the database
total_questions = float(response_set.count())
answered_questions = float(response_set.exclude(text='').count())
percent_done = (answered_questions/total_questions)*100
return '%d%% done' % percent_done
It looks like you're referring to models.JournalResponse which shouldn't exist (AttributeError?) because in the class definition the same models name is referring to django.db.models
You would need to refer to it via the actual model object, so JournalResponse.objects.filter().
In your case, you have a reverse relationship to JournalResponse from Student so you can simply use self.journalresponse_set.filter() to access JournalResponse.objects.filter(student=self)
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
Try:
self.journalresponse_set.filter(field__journal=self.assignment)
Also, your next filter line would break as well on text!=None. Use exclude(text=None) syntax instead.