models.py
class Course(models.Model):
title = models.CharField(max_length=255)
credit_hours = models.IntegerField()
instructor = models.ForeignKey(Instructor, on_delete=models.SET_NULL, null=True, related_name='course')
def __str__(self) -> str:
return self.title
class CourseTake(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='coursetake') #similar to reviews in the product class
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='course')
grade = models.PositiveIntegerField()
class Meta:
unique_together = [['student', 'course']]
class SimpleCourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ['title','credit_hours']
class CourseTakeSerializer(serializers.ModelSerializer):
course = SimpleCourseSerializer()
points = serializers.SerializerMethodField()
grade_points = serializers.SerializerMethodField()
class Meta:
model = CourseTake
fields = ['id','course', 'grade', 'points', 'grade_points']
def get_points(self, coursetake: CourseTake):
if coursetake.grade >= 90:
return '4'
elif coursetake.grade >= 70:
return '3'
elif coursetake.grade >= 50:
return '2'
return '1'
#TRY AND ERROR
#Terminal: 'CourseTake' object has no attribute 'points'
def get_grade_points(self, coursetake: CourseTake):
return coursetake.course.credit_hours * coursetake.points
I want to calculate grade points, which will be used later to calculate each student's GPA score. So the get_grade_point() will return the credit_hours * points. My problem is that the points field is not part of the model or serializer. I created a function to calculate the points for each course. Because I defined the points, Django keeps saying it's not an attribute anytime I try to access the point values. Is there a way to access the points value inside the get_grade_function?
Image for better view
Depends on what you want I suggest to use
Save method on model
def save(self, *args, **kwargs):
If you want to save result in database, Or you can use #proparty to make read only method also inside your model class if you don’t want to save it
After that you can use it easily in serializer
Related
I have this model in my django code. I want to check whether VariationPrice for a product with the variations exist. If it exists, make changes to the already existing VariationPrice else save the new VariationPrice.
The error I'm getting on saving new VariationPrice is
"<VariationPrice: >" needs to have a value for field "id" before this many-to-many relationship can be used.
The code I have in models.py is:
class Product(models.Model):
....
product_name = models.CharField(max_length=200, unique=True)
class Variation(models.Model):
....
variation_value = models.CharField(max_length=100)
class VariationPrice(models.Model):
price = models.IntegerField()
product = models.ForeignKey(Product, on_delete=models.CASCADE)
variations = models.ManyToManyField(Variation, blank=True)
def __str__(self):
if self.pk is not None:
return ", ".join(str(var) for var in self.variations.all())
else:
return ''
def save(self, *args, **kwargs):
if self.pk is None:
var_list = [i['variation_value'] for i in self.variations.values()]
vprice = VariationPrice.objects.filter(product=product,variations__variation_value__in=var_list).annotate(num_attr=Count('variations__variation_value')).filter(num_attr=len(var_list))
if vprice.exists():
self.pk = vprice.first().pk
super(VariationPrice, self).save(*args, **kwargs)
I want to write a category detail view in order to do so i want to change this function based view
def CategoryView(request, cats):
category_posts = Post.objects.filter(category=cats.replace('-', ' '))
return render(request, 'categories.html', {'cats':cats.replace('-', ' ').title(), 'category_posts':category_posts})
into the class based view. My first question: 1. How to do so?; 2.How also change the url for the view?;
path('category/<str:cats>/', CategoryView, name='category'),
Here is my models:
from django.conf import settings
from django.db import models
from django.urls import reverse
class Category(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return (self.name)
def get_absolute_url(self):
return reverse("home")
class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
category = models.ManyToManyField(Category, related_name='categories')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
#property
def categories(self):
return ', '.join([x.name for x in self.category.all()])
class Comment(models.Model):
article = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
comment = models.CharField(max_length=140)
author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse("post_list")
When you write an answer, if you don't mind, can you also write an explanation a step by step. And can you also write how did you figure out the answer. A lost a useful materials would be also helpful. Thank you in advance
You url shall look like :
path('category/<str:cats>/', CategoryClassView.as_view(), name='category')
Since in your case, you want to render 'html', below is example class view
#in your views.py
from django.views.generic import TemplateView
class CategoryClassView(TemplateView):
template_name = "categories.html"
def get_context_data(self, **kwargs):
cats = kwargs.get("cats")
category_posts = Post.objects.filter(category=cats.replace('-', ' '))
context = {'cats':cats.replace('-', ' ').title(), 'category_posts':category_posts}
return context
To answer your second part regarding how did I figure it out. Most of the the logic you have written in your function based view would be used as it, only thing you need to figure out apt attribute and method to overide. Checkout basic concept of python-inheritance and just figure out the attributes/method of particular class you want to overide. Documentation is always a good start for it.
I have a model ChildModel and it has two parent classes ActivatorModel and TimeStampedModel
Below are the three models:
The two base classes
class ActivatorModel(models.Model):
"""
ActivatorModel
An abstract base class model that provides activate and deactivate fields.
"""
INACTIVE_STATUS = 0
ACTIVE_STATUS = 1
STATUS_CHOICES = (
(INACTIVE_STATUS, _('Inactive')),
(ACTIVE_STATUS, _('Active')),
)
status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=ACTIVE_STATUS)
activate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for an immediate activation'))
deactivate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for indefinite activation'))
objects = ActivatorModelManager()
class Meta:
ordering = ('status', '-activate_date',)
abstract = True
def save(self, *args, **kwargs):
if not self.activate_date:
self.activate_date = now()
super().save(*args, **kwargs)
class TimeStampedModel(models.Model):
"""
TimeStampedModel
An abstract base class model that provides self-managed "created" and
"modified" fields.
"""
created = CreationDateTimeField(_('created'))
modified = ModificationDateTimeField(_('modified'))
def save(self, **kwargs):
self.update_modified = kwargs.pop('update_modified', getattr(self, 'update_modified', True))
super().save(**kwargs)
class Meta:
get_latest_by = 'modified'
abstract = True
The class using the above base models
class ChildModel(ActivatorModel, TimeStampedModel):
child_id = models.CharField(
max_length=36, primary_key=True, default=uuid.uuid4
)
display_name = models.CharField(blank=True, max_length=100, null=True)
status = models.CharField(max_length=20, null=True, blank=True, default='Active')
The issues is whenever I try to save some character type value in ChildModel.status, it throws an error
invalid input syntax for integer.
How to properly override the variable status and have it the properties defined in the ChildModel?
I am building my first django project, it will essentially be an assessment form. Each question will be multiple choice. There is no right or wrong answer the questions but instead a grade of what level they are at. So for each question a user can only select one answer out of the possible three options.
I have defined the following models
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Categories'
class Question(models.Model):
category = models.ForeignKey(Category, on_delete=models.PROTECT)
capability = models.TextField()
weight = models.FloatField(default=1.0)
def __str__(self):
return self.capability
class Grade(models.Model):
name = models.CharField(max_length=100)
score = models.PositiveIntegerField()
def __str__(self):
return self.name
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.PROTECT)
grade = models.ForeignKey(Grade, on_delete=models.PROTECT)
description = models.TextField()
def __str__(self):
return f'Q{self.question.id} - {self.description}'
class Area(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Assessment(models.Model):
created = models.DateTimeField(auto_now_add=True)
area = models.ForeignKey(Area, on_delete=models.PROTECT)
answers = models.ManyToManyField(Answer)
def __str__(self):
return f'{self.area} - {self.created}'
While an assessment will have multiple answers, it should only be able to contain one answer per question. Can this type of constraint be designed in the model? or it would be part of the business logic. Esentially the user will pick an answer in the webpage from a radio input so will only be able to select one. The admin page will allow me to select multiple answers form the same question.
I am just trying to find out if there is an elegant way to design this within the model, or just use the business logic to ensure only one answer per question is allowed.
I and want to auto-populate the tags field in my Django model with the value of the category & subcategory. I tried to find solutions but most of the answers leads to (auto-populate from another model). But I want to auto-populate it with value of two or more fields in the same model.
from django.db import models
from .category import cat, sub_cat
# Create your models here.
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product_name = models.CharField(max_length=200)
category = models.CharField(
max_length=50, choices=cat(), default="")
subcategory = models.CharField(
max_length=50, choices=sub_cat(), default="")
brand = models.CharField(max_length=50, default="")
desc = models.TextField(max_length=1500)
price = models.FloatField(default=0)
pub_date = models.DateField()
image = models.ImageField(upload_to="shop/images", default="")
tags =
Override the default save method:
class Product(models.Model):
fields here
def save(self, *args, **kwargs):
self.tags = self.category + '' + self.subcategory
super(Product, self).save(*args, **kwargs)
when calling .save() it will automatically take category and subcategory and concatenate.
This link should have the information you're looking for:
Django Model Field Default Based Off Another Field in Same Model
In your case I think you'd want to create a function that creates your tags based on other fields and then override the save function to set tags.
def your_function(self):
return self.category + ', ' self.subcategory
def save(self, *args, **kwargs):
if not self.tags:
self.tags= self.your_function()
super(Subject, self).save(*args, **kwargs)