Multiple Models in one Admin Screen - django

I have models:
class Acessories(models.Model):
clother = models.ForeignKey(Clother, on_delete=models.CASCADE)
acessories_type = models.ForeignKey(AcessoriesType, on_delete=models.CASCADE)
name = models.CharField(max_length=30, blank=True)
class Clother(models.Model):
MALE = 'MA'
FEMALE = 'FE'
UNISEX = 'UN'
GENDER_CHOICES = ((MALE, 'Male'), (FEMALE, 'Female'), (UNISEX, 'Unisex'))
commodity = models.ForeignKey(Commodity, related_name='commodity', on_delete=models.CASCADE)
color = models.ManyToManyField(Commodity, related_name='color')
material = models.ManyToManyField(Commodity, related_name='material')
gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=UNISEX)
How can I make it in one Admin screen?
Need to see and edit this as it was one model.
Thanks!

Try this or visit this link for more information
class AccessoryInline(admin.TabularInline):
model = Acessories
#admin.register(Clothes)
class ClothesAdmin(admin.ModelAdmin):
inlines = [
AccessoryInline,
]

Related

How to prevent two ForeignKey entries in a model from being the same for each record in Django

I have two foreign key fields that point to the same model. I would like to prevent them from having the same value. Here is my code that does not work
class Match(models.Model):
team_a = models.ForeignKey(Team, related_name='team_a', on_delete=models.CASCADE)
team_b = models.ForeignKey(Team, related_name='team_b', on_delete=models.CASCADE)
match_date_time = models.DateTimeField(validators=[validate_matchdate])
winner = models.CharField(choices=CHOICES, max_length=50, blank=True, null=True)
def clean(self):
direct = Match.objects.filter(team_a = self.team_a, team_b=self.team_b)
reverse = Match.objects.filter(team_a = self.team_b, team_b=self.team_a)
if direct.exists() & reverse.exists():
raise ValidationError('A team cannot be against itself')
You can add a CheckConstraint [Django-doc] such that the database will enforce this:
from django.db.models import F, Q
class Match(models.Model):
team_a = models.ForeignKey(
Team, related_name='matches_as_a', on_delete=models.CASCADE
)
team_b = models.ForeignKey(
Team, related_name='matches_as_b', on_delete=models.CASCADE
)
match_date_time = models.DateTimeField(validators=[validate_matchdate])
winner = models.CharField(
choices=CHOICES, max_length=50, blank=True, null=True
)
class Meta:
constraints = [
models.CheckConstraint(
check=~Q(team_a=F('team_b')), name='not_play_against_itself'
)
]

Creating a Nested Serializer with two "Sibling" Models

I'm attempting to get a JSON output similar to this:
{
name: John Doe,
best_buy_price: 420,
best_sell_price: 69,
player_profile: {
tsn_link: https://a_link.com
}
playerlistingadvanced: { # This is where I'm having the issue
sales_minute: 7,
}
}
I have three models. playerProfile being the "main" model and playerListing and playerListingAdvanced are connected to playerProfile via a one-to-one relationship. playerPfofile will have its own endpoint, but I'd also like to create an endpoint that is primarily the listings and advanced listing data (as seen above).
Here is a stripped down version of the model.py file:
class PlayerProfile(models.Model):
card_id = models.CharField(max_length=120, unique=True, primary_key=True)
name = models.CharField(max_length=420, null=True)
tsn_link = models.CharField(max_length=420, null=True)
class PlayerListing(models.Model):
player_profile = models.OneToOneField(
PlayerProfile,
on_delete=models.CASCADE,
null=True)
name = models.CharField(max_length=420, null=True)
best_sell_price = models.IntegerField(null=True)
best_buy_price = models.IntegerField(null=True)
class PlayerListingAdvanced(models.Model):
player_profile = models.OneToOneField(
PlayerProfile,
on_delete=models.CASCADE,
null=True)
sales_minute = models.DecimalField(max_digits=1000, decimal_places=2, null=True)
Here is the serializer.py I have tried, but haven't gotten to work.
class PlayerListingAdvancedForNestingSerializer(serializers.ModelSerializer):
class Meta:
model = PlayerListingAdvanced
fields = (
'sales_minute',
'last_week_average_buy',
'last_week_average_sell',
)
class PlayerListingSerializer(serializers.ModelSerializer):
player_profile = PlayerProfileForListingSerializer() # works
playerlistingadvanced = PlayerListingAdvancedForNestingSerializer() #doesn't work
class Meta:
model = PlayerListing
fields = (
'name',
'best_sell_price',
'best_buy_price',
'playerlistingadvanced',
'player_profile'
)
I'm assuming because playerListing and playerListingAdvanced are not directly related, that I'll need to do something else to make this work. Can someone point me in the right direction?
You can use SerializerMethodField. Your assuming is correct. Try this:
class PlayerListingSerializer(serializers.ModelSerializer):
player_profile = PlayerProfileForListingSerializer()
playerlistingadvanced = serializers.SerializerMethodField()
class Meta:
model = PlayerListing
fields = (
'name',
'best_sell_price',
'best_buy_price',
'playerlistingadvanced',
'player_profile'
)
def get_playerlistingadvanced(self, obj: PlayerListing):
player_profile = obj.player_profile
if hasattr(player_profile, 'playerlistingadvanced'):
serializer = PlayerListingAdvancedForNestingSerializer(instance=player_profile.playerlistingadvanced)
return serializer.data
return None

Ways to change dropdown choices in django-filter

I'm trying to change the dropdown values for the user field. I want to show the email addreses , instead of the nombre + apellido. Because in my models I have the str that returns nombre + apellido, those are the values displayed in the dropdown. How can I change those values without changing the str in the Tutor model? Tryed to do a CustomManager but didn't work.
MODEL:
class Tutor(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
nombre = models.CharField(max_length=50, blank=False, null=True)
apellido = models.CharField(max_length=50, blank=False, null=True)
biografia = models.TextField()
curriculum = models.FileField(upload_to="curriculums/", blank=True, null=True)
foto = models.ImageField(blank=True, null=True)
carrera = models.ManyToManyField(Carrera, blank=True)
linea_invest = models.ManyToManyField(Linea_Invest, blank=True)
correo = models.EmailField(blank=True, null=True)
numero_celular = models.CharField(max_length=20, blank=True, null=True)
class Meta:
verbose_name_plural = "Tutores"
verbose_name = "Tutor"
def __str__(self):
return '%s %s' % (self.nombre, self.apellido)
FILTER
class TutorFilter(django_filters.FilterSet):
nombre = CharFilter(field_name="nombre", label="Nombre",lookup_expr='icontains')
apellido = CharFilter(field_name="apellido", label="Apellido",lookup_expr='icontains')
carrera = ModelMultipleChoiceFilter(field_name= "carrera", queryset= Carrera.objects.all())
user = ModelChoiceFilter(field_name = "user", label = "correo", queryset = Tutor.objects.all())
class Meta:
model = Tutor
fields = ("nombre", "apellido", "carrera","user")
In your TutorFilter. Change
user = ModelChoiceFilter(field_name = "user", label = "correo", queryset = user.objects.all())
How I solved:
def get_tutores():
tutores = []
for tut in Tutor.objects.all():
tutores.append((tut.user.id,tut.user.email,))
return tutores
class TutorFilter(django_filters.FilterSet):
nombre = CharFilter(field_name="nombre", label="Nombre",lookup_expr='icontains')
apellido = CharFilter(field_name="apellido", label="Apellido",lookup_expr='icontains')
carrera = ModelMultipleChoiceFilter(field_name= "carrera", queryset= Carrera.objects.all())
user = ChoiceFilter( label = "correo", choices=get_tutores())
class Meta:
model = Tutor
fields = ("nombre", "apellido", "carrera","user")
See how I didn't need to change the str method in the model Tutor to display in the dropdown the tutor's emails as choices, because instead of using ModelChoiceFilter I changed to ChoiceFilter . Didn't know that you can call a function in the choices argument in the ChoiceFilter.

Django : ManyToMany, Who is the most efficient?

I hesitate between two conceptions of my models.
In my website, there are football teams. These teams contains coachs, players, directors... etc.
Currently, I modeled this like that (1) :
class Team(models.Model):
name = models.CharField(max_length=25,primary_key=True)
class Chief(models.Model):
created_at = models.DateField(auto_now_add=True)
team = models.ForeignKey(Team, null=False,on_delete=models.CASCADE)
user = models.ForeignKey(User, null=False,on_delete=models.CASCADE)
class Player(models.Model):
created_at = models.DateField(auto_now_add=True)
team = models.ForeignKey(Team, null=False,on_delete=models.CASCADE)
user = models.ForeignKey(User, null=False,on_delete=models.CASCADE)
position = models.CharField(max_length=30) #3 positions posible
class Director(models.Model):
created_at = models.DateField(auto_now_add=True)
team = models.ForeignKey(Team, null=False,on_delete=models.CASCADE)
user = models.ForeignKey(User, null=False,on_delete=models.CASCADE)
The problem is when I want to get all members of a team (chiefs, directors and players), I have to execute 3 requests.
But the advantage is when I want just all directors, I just search in Director entity !
I hesitate to delete these 3 models (Director, Player and Chief) and make 3 relations ManyToMany in Team like that (2) :
class Team(models.Model):
name = models.CharField(max_length=25,primary_key=True)
chiefs = models.ManyToManyField(User)
directors = models.ManyToManyField(User)
players_position1 = models.ManyToManyField(User)
players_position2 = models.ManyToManyField(User)
players_position3 = models.ManyToManyField(User)
Which is the most efficient way between the (1) and the (2) ?
You can use model inheritance
models.py
class TeamMember(models.Model):
created_at = models.DateField(auto_now_add=True)
team = models.ForeignKey(Team, null=False,on_delete=models.CASCADE)
user = models.ForeignKey(User, null=False,on_delete=models.CASCADE)
class Chief(TeamMember):
pass
class Director(TeamMember):
pass
class Player(TeamMember):
position = models.CharField(max_length=30)
views.py
#Get all members
members = TeamMember.objects.all()
#Only players
players = Player.objects.all()
class Team(models.Model):
name = models.CharField(max_length=25,primary_key=True)
class MemberQuerySet(models.QuerySet):
def chiefs(self):
return self.filter(position='a')
def directors(self):
return self.filter(position='b')
def players(self):
return self.filter(position__in=['c', 'd', 'e'])
class Member(models.Model):
created_at = models.DateField(auto_now_add=True)
team = models.ForeignKey(Team, models.CASCADE, related_name="members")
user = models.ForeignKey(User, models.CASCADE)
position = models.CharField(max_length=1, choices=(
('a', 'chief'),
('b', 'director'),
('c', 'player position 1'),
('d', 'player position 2'),
('e', 'player position 3'))
objects = MemberQuerySet.as_manager()
Now you can get all members of a team or just the players with just one hit on the database
members = Team.objects.get(pk='someteam').members
players = Team.objects.get(pk='someteam').members.players()

Display data from another model in admin panel

How to display in OrderAdmin: Basket owner, products, quantity of products?
I try Inline:
admin.py:
class BasketInline(admin.TabularInline):
model = Basket
class OrderAdmin(admin.ModelAdmin):
inlines = [
BasketInline,
]
admin.site.register(Order, OrderAdmin)
but it does not work.
class Basket(models.Model):
owner = models.ForeignKey(User, related_name='user_basket', verbose_name='Owner')
name = models.CharField("Basket_Name", max_length=30)
products = models.ManyToManyField('Product', through='BasketProduct', blank=True, null=True)
class BasketProduct(models.Model):
product = models.ForeignKey('Product')
basket = models.ForeignKey('Basket')
quantity = models.IntegerField()
class Product(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField()
unit_price = models.DecimalField(max_digits=5, decimal_places=2)
desc = models.TextField()
category = models.ManyToManyField(Category)
class ShippingOptions(models.Model):
name = models.CharField(max_length=50)
price = models.DecimalField(max_digits=5, decimal_places=2)
time = models.CharField(max_length=150)
class Order(models.Model):
bask = models.OneToOneField(Basket)
shipp = models.OneToOneField(ShippingOptions)
Maybe I need a different way. Please any help. Thanks
You need foreignKey on Order in you Basket model:
class Basket(models.Model):
owner = models.ForeignKey(User, related_name='user_basket', verbose_name='Owner')
name = models.CharField("Basket_Name", max_length=30)
products = models.ManyToManyField('Product', through='BasketProduct', blank=True, null=True)
owner = models.ForeignKey(Owner, blank=True, verbose_name='Owner')
or you have error in first model row:
owner = models.ForeignKey(Owner, related_name='user_basket', verbose_name='Owner')