Django Model Design (Big model vs multiple) - sql

I have a question about designing my models. Suppose I have a following model:
class Comment(models.Model):
who = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
text = models.CharField(max_length=1000)
likes = models.IntegerField(default=0)
parent_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='child_comments')
Now I would like models for multiple topics (ShoppingList, Games,...). I came to two possible solutions and need help with deciding more suitable one.
1) Make Comment abstract and extend it for every new model wanted.
class ShoppingListComment(Comment):
shopping_list = models.ForeignKey(ShoppingList, related_name='shopping_comments', on_delete=models.CASCADE)
I could then query this game comments with something like:
ShoppingListComment.objects.all()
2) Add extra nullable Foreing keys directly to comment:
class BigCommentModel(models.Model):
who = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
text = models.CharField(max_length=1000)
likes = models.IntegerField(default=0)
parent_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='child_comments')
shopping_list = models.ForeignKey(ShoppingList, related_name='shopping_comments', on_delete=models.CASCADE, null=True),
game = models.ForeignKey(Game, related_name='game_comments', on_delete=models.CASCADE, null=True)
I could then query this game comments with something lile:
BigCommentModel.objects.filter(game__isnull=False)

Related

How to avoid duplicates when Prefetch m2m related objects with soft deletable models?

I want to get list of accounts with not deleted relations.
Models
class User(models.Model):
accounts = models.ManyToManyField(
to='billing.Account',
through='custom_auth.UserAccount',
through_fields=('user', 'account'),
related_name='users',
)
deleted = models.DateTimeField(
verbose_name=_('Deleted at'),
blank=True,
null=True,
db_index=True
)
objects = UserQuerySet.as_manager()
class UserAccount(models.Model):
user = models.ForeignKey(
to='custom_auth.User',
on_delete=models.CASCADE)
account = models.ForeignKey(
to='billing.Account',
blank=True,
null=True,
on_delete=models.CASCADE)
deleted = models.DateTimeField(
verbose_name=_('Deleted at'),
blank=True,
null=True,
db_index=True
)
class Account(models.Model):
_users = models.ManyToManyField('custom_auth.User', blank=True)
User Manager
class UserQuerySet(models.QuerySet):
def prefetch_accounts_for_api(self, request):
accounts_qs = Account.objects.all()
user_account_qs = UserAccount.objects.filter(
user=request.user,
account_id=OuterRef('pk'),
deleted__isnull=True
)[:1]
accounts_qs = accounts_qs.filter(
useraccount=user_account_qs
)
return self.prefetch_related(Prefetch(
'accounts',
queryset=accounts_qs,
to_attr='enabled_accounts'
))
The problem is that when there are two rows in useraccount table (1 deleted and 1 not deleted) and i execute the query:
User.objects.all().prefetch_accounts_for_api(request)
User have duplicate of not deleted account relation in enabled_accounts attribute.
How can i get only one actual account in enabled_accounts?
Using PostgreSQL and Django 3.1.7

from sql to Django... i don't understand

i have 3 models (protocollo_pratica, protocollo_soggetto and protocollo_anaprat) and i need extract for each protocollo_pratica a list of soggetti with a specific "tipo" but i don't understand how to make this in django views. Thank you so much for your help.
`
this is my models.py :
`
from django.db import models
# Create your models here.
class Soggetto(models.Model):
cognome = models.CharField(max_length=100, null=True)
nome = models.CharField(max_length=100, null=True)
comune_nascita = models.CharField(max_length=100, null=True)
data_nascita = models.DateField(null=True)
codice_fiscale = models.CharField(max_length=16, null=True)
def __str__(self):
"""String for representing the MyModelName object (in Admin site etc.)."""
return self.nome
class Pratica(models.Model):
oggetto = models.CharField(max_length=100)
anagrafe = models.ManyToManyField(Soggetto,
through='Anaprat',
through_fields=('pratica', 'soggetto'),)
def __str__(self):
"""String for representing the MyModelName object (in Admin site etc.)."""
return self.oggetto
class Anaprat(models.Model):
tipo=models.CharField( max_length=50)
pratica=models.ForeignKey("Pratica", related_name='pratiche', on_delete=models.CASCADE)
soggetto=models.ForeignKey("Soggetto", related_name='soggetti', on_delete=models.CASCADE)
def __str__(self):
"""String for representing the MyModelName object (in Admin site etc.)."""
return f"{self.tipo, self.soggetto}"`
and this is my sql query :
`SELECT
p.id,
pa.tipo tipo,
ps.cognome,
ps.nome,
ps.data_nascita,
ps.comune_nascita
from
(SELECT
id id
from protocollo_pratica pp ) p,
protocollo_anaprat pa
left JOIN protocollo_soggetto ps
on ps.id=pa.soggetto_id
where p.id=pa.pratica_id`

Cannot resolve keyword into field error while using drf model serializer and search_fields within field set?

SerializerClass:
class VacancySerializer(serializers.ModelSerializer):
organization_small_name = serializers.CharField(source='organization.short_name', read_only=True)
class Meta:
model = Vacancy
fields = ['organization', 'description', 'specs', 'type', 'publication_date',
'is_published', 'withdrawal_data', 'organization_small_name', ]
read_only_fields = ['publication_date', 'is_published', 'withdrawal_data',]
ViewSet:
class VacancyViewSet(viewsets.ModelViewSet):
queryset = Vacancy.objects.all()
serializer_class = VacancySerializer
filter_backends = [filters.SearchFilter]
search_fields = ['organization_small_name']
...
Model:
class Vacancy(models.Model):
organization = models.OneToOneField(DictOrganization, on_delete=models.CASCADE, related_name='vacancies')
description = models.TextField('Описание')
specs = models.ManyToManyField(DictSpec, blank=True)
type = models.CharField('Тип', max_length=20, choices=VacancyType.choices(), default=VacancyType.PRACTICE.value)
publication_date = models.DateField('Дата публикации', null=True, blank=True)
is_published = models.BooleanField('Опубликовано', default=False)
withdrawal_data = models.DateField('Дата снятия с публикации', null=True, blank=True)
My goal is to make API search by 'organization_small_name' field
that is in VacancySerializer.
Server runs successfully, but as soon as i add ?search parameter, i get next error:
Why it doesn't recognize 'organization_small_name' field, even thought it is decribed in serializer, and how can i fix it?

Django, how to modify output of a related model serizlizer?

I have a model which has several ForeignKeys:
class Employee(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="staff", null=False, blank=False)
user = models.ForeignKey(to=User, blank=False, null=False, on_delete=models.CASCADE)
roles = models.ManyToManyField(to=Role, blank=False)
How do I use a fields from Company and User in Employee model? I need them for __str__.
you can access these as attributes of the self.company or self.user, since self.company will return a Company object.
You thus can work with:
class Employee(models.Model):
company = models.ForeignKey(
Company,
on_delete=models.CASCADE,
related_name='staff'
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE
)
roles = models.ManyToManyField(Role)
def __str__(self):
return f'{self.company} {self.user.username}'
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Django REST framework many to many serializer

I got models:
class Car:
name = models.CharField(max_length=50, blank=True, default='')
class Wheel:
name = models.CharField(max_length=50, blank=True, default='')
cars = models.ManyToManyField(Car)
and serializers:
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
fields = ('name')
class WheelSerializer(serializers.ModelSerializer):
cars = CarSerializer(many=True, required=False)
class Meta:
model = Wheel
fields = ('name', 'cars')
It's works fine with Wheel case, it's shows me wheels and cars inside them. But I want to call cars and see wheels inside Cars. It's possible? Thanks!
Solution is to create new serializers:
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
fields = ('name')
class WheelSerializer(serializers.ModelSerializer):
class Meta:
model = Wheel
fields = ('name', 'cars')
class CarWheelSerializer(serializers.ModelSerializer):
cars = CarSerializer(many=True, required=False)
class Meta:
....
and WheelCarSerializer same way.