How change a function based view into a class based? - python-3.x

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.

Related

How to get queryset data in django which picked from two range date calender forms (date_from - date_to)?

i've tried to follow this tutorial: https://www.youtube.com/watch?v=04L0BbAcCpQ&t=5133s (minutes: 2:10:27)
as creator said, to access the date directly, we need to code double underscore as "created__date". That's because mentioned in django documentation perfectly the same way. this still didn't get me result as the creator had. Meanwhile, when i disabled my filter (qs = Sale.objects.filter(date=date_from) in views.py) and print it as object it's worked. Also when i moved queryset code a head from if block code, it's print perfectly compiled from qs = Sale.objects.all() and gave me result all of 3 data of it.
#here is the views.py:
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Sale
from .forms import SalesSearchForm
# from django.views.generic.list import ListView
# Create your views here.
def home_view(request):
form = SalesSearchForm(request.POST or None)
if request.method == 'POST':
date_from = request.POST.get('date_from')
date_to = request.POST.get('date_to')
chart_type = request.POST.get('chart_type')
print(date_from, date_to, chart_type)
# qs = Sale.objects.all()
#atau bisa diganti dengan filter tertentu untuk seleksi data yang di inginkan:
qs = Sale.objects.filter(created__date=date_from)
obj = Sale.objects.get(id=2)
print(qs)
print(obj)
# hello = 'hello world from sales/views.py'
context = {
# 'hello': hello,
'form': form,
}
return render(request, 'sales/home.html', context)
here is the model.py (pay attention at Class Sale):
from django.db import models
from products.models import Product
from customers.models import Customer
from profiles.models import Profile
from django.utils import timezone
from .utils import generate_code
from django.shortcuts import reverse
# Create your models here.
class Position(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
price = models.FloatField(blank=True)
created = models.DateTimeField(blank=True)
def save(self, *args, **kwargs):
self.price = self.product.price * self.quantity
return super().save(*args, **kwargs)
def __str__(self):
return f"id: {self.id}, product: {self.product.name}, quantity: {self.quantity}"
class Sale(models.Model):
transaction_id = models.CharField(max_length=12, blank=True)
positions = models.ManyToManyField(Position)
total_price = models.FloatField(blank=True, null=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
salesman = models.ForeignKey(Profile, on_delete=models.CASCADE)
created = models.DateTimeField(blank=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Sales for the amount of ${self.total_price}"
def get_absolute_url(self):
return reverse('sales:detail', kwargs={'pk': self.pk})
def save(self, *args, **kwargs):
if self.transaction_id == "": # jika transaksi sama dengan blank
self.transaction_id = generate_code() # maka kode transaksi id digenerate dgn fungsi '***'
if self.created is None: # jika created = none
self.created = timezone.now() # maka created = timezone.now
return super().save(*args, **kwargs)
def get_positions(self): #sebuah custom method untuk mendapatkan semua data di class position related ke sale object
return self.positions.all() #harus refere ke manytomany field (field positions)
class CSV(models.Model):
file_name = models.FileField(upload_to='csvs')
activated = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.file_name)
Here is the forms.py:
from django import forms
CHART_CHOICES = (
('#1', 'Bar chart'),
('#2', 'Pie chart'),
('#3', 'Line chart'),
)
class SalesSearchForm(forms.Form):
date_from = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
date_to = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
chart_type = forms.ChoiceField(choices=CHART_CHOICES)
hy thanks for trying to figured out. I've been working to solve this for almost 2 days. and my solution is worked!
the problem is when i tried to select the date from the forms for the "between date" is not working. it just shows when i picked exact date input. So i read the django documentation over again. and i change the code from this (views.py):
qs = Sale.objects.filter(created__date=date_from)
to this:
qs = Sale.objects.filter(created__range=(date_from, date_to))
That's it! Hopefully anyone find this helpful. thanks!

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)

Getting TypeError: __init__() missing 1 required positional a rgument: 'on_delete'

'HOw to reslove this erroe I am using Django 3.0'
from django.db import models
# Create your models here.
class Topic(models.Model):
top_name=models.CharField(max_length=264,unique=True)
def __str__(self):
return self.top_name
class Webpage(models.Model):
topic= models.ForeignKey(Topic)
name = models.CharField(max_length=264,unique=True)
url = models.URLField(unique= True)
def __str__(self):
return self.name
class AccessRecord(models.Model):
name = models.ForeignKey(Webpage)
date = models.DateField()
def __str__(self):
return str(self.date)
I copied code of Django 1 version and I am using Django 3.0 version.
File "C:\Users\himan5hu\Documents\HTML\My_Django\first_project\first_app\models.py", line 7, in
class Webpage(models.Model):
File "C:\Users\himan5hu\Documents\HTML\My_Django\first_project\first_app\models.py", line 8, in Webpage topic= models.ForeignKey(Topic)
topic= models.ForeignKey(Topic)
Since django-2.0, it is mandator to specify an on_delete=… parameter [Django-doc] for a ForeignKey. Before django-2.0, it was by default CASCADE.
on_delete=… is a parameter that specifies what to do in case the target object is deleted. In case of CASCADE the Webpage will thus be removed if it points to a Topic that is removed.
You thus can fix this with:
from django.db import models
class Topic(models.Model):
top_name=models.CharField(max_length=264,unique=True)
def __str__(self):
return self.top_name
class Webpage(models.Model):
topic= models.ForeignKey(Topic, on_delete=models.CASCADE)
name = models.CharField(max_length=264, unique=True)
url = models.URLField(unique=True)
def __str__(self):
return self.name
class AccessRecord(models.Model):
name = models.ForeignKey(Webpage, on_delete=models.CASCADE)
date = models.DateField()
def __str__(self):
return str(self.date)
You will need to alter this in existing migration files as well.
It might however be useful to inspec the documentation, and look if another option might be more approriate.

How to access/override defaults on parent's attribute in SQL Alchemy?

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'
}

Resources