How to access/override defaults on parent's attribute in SQL Alchemy? - python-3.x

I have the following classes: Item, StoneSword, IronSword, Apple, Steak
Item is the parent class, and the Swords and food inherit the Item class. I want to have a bunch of different functions and descriptions for each of these classes.
I completely understand the function side of things, but I am struggling to figure out how to override the default description with the children classes.
I am currently using single table inheritance with SQLAlchemy.

Credit goes to Mike Bayer for helping me figure out how to override __init__() to suit my needs. If anybody can find a more elegant solution, I will be glad to accept that answer instead.
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String, default="User")
fullname = Column(String)
email = Column(String)
type = Column(String)
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'user'
}
def __init__(self, **kwargs):
super().__init__(**kwargs)
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}', fullname='{self.fullname}', email='{self.email}')>"
def is_admin(self):
print(f"I, {self.name}, am NOT an admin")
class Admin(User):
def __init__(self, **kwargs):
kwargs.setdefault("name", "Admin")
super().__init__(**kwargs)
__mapper_args__ = {
'polymorphic_identity': 'admin'
}

Related

How change a function based view into a class based?

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.

Attribute Error in python, object has no attribute

I am new to inheritance in classes and for some reason, the attributes in this code don't seem to be sharing correctly. I'm not sure what the issue is.
class Person:
def __init__(self, name, age, occupation):
self.name = name
self.age = age
self.occupation = occupation
def say_hello(self):
print(f"Hello, my name is {self.name}.")
def say_age(self):
print(f"I am {self.age} years old.")
class Superhero(Person):
def __init__(self, name, age, occupation, secret_identity, nemesis):
self.secret_identity = secret_identity
self.nemesis = nemesis
hero = Superhero("Spider-Man", 17, "student", "Peter Parker", "Green Goblin")
print(hero.name())
It looks like you're not calling the super constructor in your Superhero class.
You should do as follow:
class Superhero(Person):
def __init__(self, name, age, occupation, secret_identity, nemesis):
super().__init__(name, age, occupation)
self.secret_identity = secret_identity
self.nemesis = nemesis
BTW: you didn't define a function named name. If you want to print the name you should remove the (), e.g print(hero.name)

Django model constraint or business logic

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.

Access manyTomany field (Label) from category class via subclass(Products) Category-> Products -> Labels

Here is the code of my models file:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
name = models.CharField(max_length=255)
price = models.DecimalField(decimal_places=2, max_digits=9)
def __str__(self):
return self.name
class Label(models.Model):
name = models.CharField(max_length=255)
products = models.ManyToManyField(Product, related_name='labels')
def __str__(self):
return self.name
Now I want to access manyTomany field i.e. Label from Category
please help me
Thanks in advance
You can try like this.
# first get the single category object
category = Category.objects.get(pk=1)
# querying products in this category
products = category.products.all()
# now filter the Label model based on the category products
labels = Label.objects.filter(products__in=products)

In Flask REST API do I need to create different models and resources to manipulate different rows of the same table?

I am new to API and I am creating a FLask Restful API.I was wondering that do I need to create new model and resource classes for any row manipulation I want to do in my DB? For example I have created a student in my DB. On creation he does not have any grades and so I created StudentModel and StudentResource and used table Student. When I need to update grades using PUT request do I need to create a SudentGradeModel and StudentGradeResource also accessing student table?
Every Model class includes helper functions that the Resource class uses by importing the Model class. The Resource classes only have GET, POST, PUT and DELETE methods.
class StudentModel(db.Model):
__tablename__ = 'Student'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
class_sec = db.Column(db.String(4))
def __init__(self, id, name, class_sec):
self.id = id
self.name= name
self.class_sec = class_sec
from flask_restful import Resource, reqparse
from models.student_model import StudenteModel
# noinspection PyMethodMayBeStatic
class StudentResource(Resource):
parser = reqparse.RequestParser()
parser.add_argument('id', type=int, required=True, help='Every Student must have an ID')
parser.add_argument('name', type=str, required=True, help='Every Student must have a name')
parser.add_argument('class', type=str, required=True, help='Every Student must be assigned a class and section')
def get(self, id):
pass
def post(self, id):
pass
class StudentGradeModel(db.Model):
__tablename__ = 'Student'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
grade = db.Column(db.String(2), primary_key=True)
def __init__(self, id, grade):
self.id = id
self.grade = grade
# noinspection PyMethodMayBeStatic
class StudentGradeResource(Resource):
parser = reqparse.RequestParser()
parser.add_argument('id', type=int, required=True, help='Student must have an ID to access table')
parser.add_argument('grade', type=str, required=True, help='Student must have a grade to be assigned')
def get(self, id):
pass
def post(self, id):
pass
Similarly if I wanted to only update the section would I have to create a similar Classe with a PUT request.
Thank You
From the question, I'm assuming that one student can only have one grade or no grade at all, because if they can have more than one, a grade must be in a separate table.
The table creation SQL looks like this:
CREATE TABLE student (
id INT PRIMARY KEY,
name VARCHAR(30) NOT NULL,
class_sec CHAR(4) NOT NULL,
grade INTEGER
);
(I changed the datatype for grade since numeric data shouldn't be stored as string)
No, you can't, and should not have two models for the same table. The model should represent the table itself.
class StudentModel(db.Model):
__tablename__ = 'Student'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False)
class_sec = db.Column(db.String(4), nullable=False)
grade = db.Column(db.Integer)
def __init__(self, id, name, class_sec):
self.id = id
self.name= name
self.class_sec = class_sec
On the other hand, you can have more than one resource to interface a table. However, each resource is associated with one route, and you shouldn't have a separate resource for grade, unless you need another route for that, which I think you don't.
class Student(Resource):
...
def put(self, id):
request_body = request.get_json()
# do your things here

Resources