There are 3 models (companies, divisions and staffgroups) to display as list.
I am trying to create a class base view extended from ListView to list various models through passing the model name in the URLpatterns.
I had created individual class view for each model but there are essentially copy paste codes. Is there a way to streamline the code into just one class and get the model from urlpath.
models.py
from django.db import models
...
class Company(models.Model):
id = models.CharField(max_length=5, primary_key=True)
name = models.CharField(max_length=100)
is_active = models.BooleanField()
...
class Division(models.Model):
id = models.CharField(max_length=5, primary_key=True)
name = models.CharField(max_length=100)
is_active = models.BooleanField()
...
class StaffGroup(models.Model):
name = models.CharField(max_length=20)
is_active = models.BooleanField()
...
urls.py
from django.urls import path
from srrp.views import srrpIndexView, srrpListView
app_name = 'srrp'
urlpatterns = [
path('', srrpIndexView.as_view(), name='srrp_index'),
path('<str:modelname>', srrpListView.as_view(), name='srrp_list'),
]
views.py
class srrpListView(ListView):
template_name = 'srrp/srrplist.html'
model = self.kwargs['modelname'] # I know this is wrong, this is just placeholder for the right solution
paginate_by = 10
Subclass get_queryset. (Bookmark Classy Class-based views)
def get_queryset(self):
model = self.kwargs['modelname']
if model == 'foo':
return Foo.objects.all()
if model == 'bar':
return Bar.objects.all()
if model == 'green_bar':
return Bar.objects.filter( colour='green' )
...
raise ValueError(
f'This shouldn't be possible: model = "{model}"'
If you don't want any "special" models, you could either look up the right model in a dict of classes:
klass = MODEL_CLASSES[model] # KeyError if bad model in URL
return klass.objects.all()
or you could use a Django function whose name I have forgotten to get the model class by app and model names.
Solved.
views.py
class srrpListView(ListView):
template_name = 'srrp/srrplist.html'
paginate_by = 10
def get_queryset(self):
modelname = self.kwargs['modelname']
ctype = ContentType.objects.get(app_label='srrp', model=modelname)
model = ctype.model_class()
return model.objects.all()
Related
Context: I am writing the test cases for testing the django model and serializer for a django-rest api.
Models.py looks like this:
from django.db import models
import uuid
class User(models.Model):
user_id = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4)
first_name = models.CharField(max_length=100)
second_name = models.CharField(max_length=100)
def getuuid(self):
return str(self.user_id)
class Workout(models.Model):
user_id = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
hours = models.FloatField()
class Meta:
constraints = [
models.CheckConstraint(
check=models.Q(hours__gte=0),
name="Hours should be positive"
)
]
class Vacation(models.Model):
user_id = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
times = models.IntegerField()
class Meta:
constraints = [
models.CheckConstraint(
check=models.Q(times__gte=1) & models.Q(times__lte=15),
name="Valid range is 1 to 15 inclusive"
)
]
Serializer.py looks like this:
from rest_framework import serializers
from .models import User, Workout, Vacation
class UserSerializer(serializers.ModelSerializer):
class Meta:
model= User
fields= '__all__'
class WorkoutSerializer(serializers.ModelSerializer):
class Meta:
model= Workout
fields= '__all__'
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model= Vacation
fields= '__all__'
tests.py looks like this:
from django.test import TestCase
from .models import *
from .serializers import *
class UserTest(TestCase):
#classmethod
def setUpTestData(cls):
super(UserTest, cls).setUpTestData()
cls.u1 = User.objects.create(
first_name = "Jack",
second_name = "Mueller",
#hours = 3.5,
#times = 3
)
cls.w1 = Workout.objects.create(
hours = 2,
user_id = cls.u1
)
cls.t1 = Vacation.objects.create(
times = 2.5,
user_id = cls.u1
)
cls.w2_val = {
"hours":6,
"user_id": cls.u1
}
cls.w2 = Workout.objects.create(**cls.w2_val)
cls.w2_ser = WorkoutSerializer(cls.w2)
cls.w2_deser = WorkoutSerializer(data=cls.w2_val)
def test_user_model(self):
self.assertEquals(len(User.objects.all()), 1)
def test_serializer(self):
print(self.w2_deser.is_valid()) # return False
print(self.w2_deser.errors) # {'user_id': [ErrorDetail(string='“User object (3a598312-5f3d-4adb-b4fc-c415fb024e8a)” is not a valid UUID.', code='invalid')]}
My Questions:
Why do I get False for w2_deser.is_valid() ?
How do I resolve the subsequent error (w2_deser.errors)? I tried setting user_id=cls.u1.user_id, this too did not address the issue.
Although the times field in the Vacation class is defined as an Integer, it accepts the floating point value. What is the reason behind this and how do I address it? (I tried defining custom validators but it did not work.)
I have done my fair bit of scavenging the internet for solution/information and also referred the official documentation. However, my questions remain unresolved. I am fairly new to Django and Rest. So any advice on the matter will be gladly welcomed. Thank you.
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)
I'm new to django and struggling, I look over google but couldn't find anything that can help.
Here is my model:
from django.db import models
# from django.contrib.auth.models import
class Order(models.Model):
table_id = models.IntegerField(unique=True)
meal = models.ManyToManyField('meals')
# Meal = models.ForeignKey('Meals',on_delete=models.CASCADE)
#property
def total_price(self):
price = self.meal.objects.all().aggregate(total_price=models.Sum('meals__price'))
return price['total_price']
class Meals(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=5)
Here is my serializer.py :
from rest_framework import serializers
from cafe_app import models
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = models.Meals
fields = ['id','name','price',]
class OrderSerializer(serializers.ModelSerializer):
**meal = MealSerializer(read_only=True,many=True)**
class Meta:
model = models.Order
fields = ['table_id','meal',]
When I comment meal = MealSerializer(read_only=True,many=True) line then it shows input as table_id and meal where meal values are as Meal Object (1), Mean Object (2) ... .
My questions :
How to display meal Object value instead of it as object.
How Can I use total_price method in my view/serializer.
How to see the flow like how it flows from which class to which class call goes and what is type and value of structure that I received.
Thanks.
How to display meal Object value instead of it as object.
Use the __str__ method on Meal.
How Can I use total_price method in my view/serializer.
Define the annotation in your view's queryset, then add the custom field to the serializer. Do not add it to your model unless it's a one-off thing. The way you have it is pretty inefficient as it'll generate many queries for a list view.
How to see the flow like how it flows from which class to which class call goes and what is type and value of structure that I received.
Use a debugger in an IDE like PyCharm, PDB, or the classic print statements.
Below are the corrections I've suggested for 1 and 2.
# models.py
from django.db import models
class Order(models.Model):
table_id = models.IntegerField(unique=True)
meal = models.ManyToManyField('meals')
class Meals(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=5)
def __str__(self):
# This method defines what the string representation an instance.
return f'{self.name}: ${self.price}'
# serializers.py
from rest_framework import serializers
from cafe_app import models
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = models.Meals
fields = ['id','name','price',]
class OrderSerializer(serializers.ModelSerializer):
total_price = serializers.FloatField(read_only=True)
meal = MealSerializer(read_only=True,many=True)
class Meta:
model = models.Order
fields = ['table_id','meal', 'total_price']
# views.py
class OrderView(ViewSet): # or View.
queryset = Order.objects.annotate(
total_price=Sum('meal__price')
)
I am getting this following error when trying to run
RuntimeError: Model class first_app.models.Topic doesn't declare an
explicit app_label and isn't in an application in INSTALLED_APPS.
[![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.DateTimeField()
def __str__(self):
return str(self.date)][1]][1]
The Problem is in module app:
first_app.apps.py
Change:
class First_appConfig(AppConfig):
name = 'fist_app'
To:
class First_appConfig(AppConfig):
name = 'name_project.fist_app'
verbose_name = 'Fist_app'
Hope this helps you! I had the same problem so I was able to solve it in a similar way.👍🏼
Based on the output of your session, it looks like you did not add 'first_app' to the INSTALLED_APPS setting [Django-doc]. In your settings.py file, you need to add this:
# settings.py
# …
INSTALLED_APPS = [
# …
'first_app',
]
Then you will need to rerun the makemigrations command, since now it could not find your first_app, and hence did not make any migrations at all.
I'm starting a web-like esports. I have a class called the game and Tournament.
Tournament has a foreignkey with game. Game has objects pubg and clashroyale. When Tournament is created with game pubg it has to have a attribute called "prize_per_kill". but not with other games. It has to be unique to that Tournament when created with that game. How can i do this?
I thought about using manytomanyfield but a single Tournament has only one Game. so it must be foreignkey.
I expect special attributes to that tournament that i can iterate through in detail page.
'''
class Tournament(models.Model):
game = models.ForeignKey(Game, on_delete=models.CASCADE)
players = models.ManyToManyField(User,through="Subscription")
max_players = models.IntegerField(default=100)
tourney_type = models.CharField(max_length=20)
price = models.IntegerField()
time = models.DateTimeField()
tourney_id = models.CharField(max_length=50)
tourney_pass = models.CharField(max_length=15)
first_prize = models.IntegerField()
second_prize = models.IntegerField()
third_prize = models.IntegerField()
'''
'''
class Game(models.Model):
users = models.ManyToManyField(User, through="Membership")
name = models.CharField(max_length=20)
desc = models.TextField()
'''
You can create an abstract Game model, PubgGame and ClashRoyaleGame models that inherit from your abstract model. That will give you two main flexibilities:
As Game will be an abstract model, no table will be created for it. You'll only have tables for PubgGame etc. game models.
You can add specific fields for each game such as prize_per_kill.
But using this solutions will arise a problem; you abstract models can't be used as ForeignKey in other models. So you need to find a way to represent your PubgGame and ClashRoyaleGame models in one ForeignKey field. Django has a special field for that: GenericForeignKey. You need to point to a CoontentType and an PositiveIntegerField to your GenericForeignKey to be able store primary key id's of your game models.
# models.py
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
class Game(models.Model):
users = models.ManyToManyField(User, through="Membership")
name = models.CharField(max_length=20)
desc = models.TextField()
class Meta:
abstract = True
class PubgGame(Game):
prize_per_kill = models.TextField() # I dont know what prize_per_kill means :)
class ClashRoyaleGame(Game):
some_other_field = models.TextField()
class Tournament(models.Model):
players = models.ManyToManyField(User,through="Subscription")
max_players = models.IntegerField(default=100)
tourney_type = models.CharField(max_length=20)
price = models.IntegerField()
time = models.DateTimeField()
tourney_id = models.CharField(max_length=50)
tourney_pass = models.CharField(max_length=15)
first_prize = models.IntegerField()
second_prize = models.IntegerField()
third_prize = models.IntegerField()
# GenericForeignKey related fields
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
game = GenericForeignKey('content_type', 'object_id')
Then you can use these fields like:
>>> from your_ap.models import Tournament, PubgGame
>>> pubg_game = PubgGame.objects.create(prize_per_kill="some value")
>>> tournament = Tournament.objects.create(game=pubg_game) # I'm not setting other fields for simplicity.
>>> tournament.save()
>>> tournament.game_object # This will give you a PubgGame model object