Django Models.py Database Design Feedback - python

Based on my previous question and feedback I received I have redesigned my Models and need some feedback before I run the "syncdb".
My concerns are mostly ForeignKeys and the one ManyToManyField in the Restaurant table. Should also the ManyTomany field have the through='' value and what the value should be?
Any feedback is appreciated!
Models
class Restaurant(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='name', blank=True)
address = models.CharField(max_length=100L, blank=True)
city_id = models.ForeignKey('City', related_name="restaurant_city")
location_id = models.ForeignKey('Location', related_name="restaurant_location")
hood_id = models.ForeignKey('Hood', null=True, blank=True, related_name="restaurant_hood")
listingrole_id = models.ForeignKey('Listingrole', related_name="restaurant_listingrole")
cuisine_types = models.ManyToManyField('Cuisinetype', null=True, blank=True, related_name="restaurant_cuisinetype")
class Meta:
db_table = 'restaurant'
class City(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='city')
state = models.CharField(max_length=50L, db_column='state', blank=True, null=True)
class Meta:
db_table = 'city'
class Cuisinetype(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='cuisine', blank=True) # Field name made lowercase.
class Meta:
db_table = 'cuisinetype'
class Location(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='location', blank=False, null=False)
city = models.ForeignKey('City', related_name="location_city")
class Meta:
db_table = 'location'
class Hood(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='hood')
city = models.ForeignKey('City', related_name='hood_city')
location = models.ForeignKey('Location', related_name='hood_location')
class Meta:
db_table = 'hood'
class Listingrole(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=50L, db_column='listingrole', blank=True) # Field name made lowercase.
class Meta:
db_table = 'listingrole'
....

Having into account the concept and meaning of coisine_types you don't have to make the relationship using through keyword. You use it (mostly) when there is some information about the relation it self.
According Django documentation:
The most common use for this option is when you want to associate extra data with a many-to-many relationship.
See explanation here: Extra fields on many-to-many relationships

Related

Show secondary foreign key values in the inline django admin

models.py
class FarmerAdvisory(BaseModel):
id = models.AutoField(db_column='id', primary_key=True)
title = models.CharField(db_column='title', max_length=200, null=True, blank=True)
description = models.CharField(db_column='description', max_length=750, null=True, blank=True)
farmer_id = models.ForeignKey(Farmer, on_delete=models.CASCADE, null=True, db_column='farmer_id')
class Meta:
verbose_name = 'Farmer Advisory'
verbose_name_plural = 'Farmer Advisories'
managed = True
db_table = 'farmer_advisory'
class ReplyFarmerAdvisory(BaseModel):
reply = models.CharField(db_column='reply', max_length=750, null=True, blank=True)
label = models.CharField(db_column='label', max_length=100, null=True, blank=True)
farmer_advisory_id = models.ForeignKey(FarmerAdvisory, on_delete=models.CASCADE, db_column='farmer_advisory_id')
objects = models.Manager()
class Meta:
verbose_name = 'Reply Farmer Advisory'
verbose_name_plural = 'Reply Farmer Advisories'
managed = True
db_table = 'reply_farmer_advisory'
class AdvisoryMedia(models.Model):
id = models.AutoField(db_column='id', primary_key=True)
farmer_advisory_id = models.ForeignKey(FarmerAdvisory, on_delete=models.CASCADE,
db_column='farmer_advisory_id',
null=True, blank=True)
reply_farmer_advisory_id = models.ForeignKey(ReplyFarmerAdvisory, on_delete=models.CASCADE,
db_column='reply_farmer_advisory_id', null=True, blank=True)
farmer_media_file = models.CharField(db_column='farmer_media_file', max_length=50, null=True, blank=True)
is_active = models.BooleanField(db_column='is_active', null=False, default=True)
reply_media_file = models.FileField(upload_to=content_file_name, null=True, blank=True,
db_column='reply_media_file')
class Meta:
verbose_name = 'Advisory Media'
verbose_name_plural = 'Advisories Media'
managed = True
db_table = 'advisory_media'
admin.py
class AdvisoryMediaInline(NestedStackedInline):
model = AdvisoryMedia
extra = 0
class ReplyFarmerAdvisoryInline(NestedStackedInline):
model = ReplyFarmerAdvisory
extra = 1
inlines = [AdvisoryMediaInline]
class FarmerAdvisoryAdmin(NestedModelAdmin):
inlines = [ReplyFarmerAdvisoryInline]
I want to show the fields with respect to the farmer advisory. But when i am adding fk_name = 'farmer_advisory_id' inside AdvisoryMediaInline, i am getting error stating
ValueError: fk_name 'farmer_advisory_id' is not a ForeignKey to
'farmer.ReplyFarmerAdvisory'.
But i want to show the farmer advisory related fields which is not coming by itself.
I think what is happening is the model is looking for values with respect to the to foreign key reply advisory media instead of farmer advisory media.
Please let me know if my question is understandable, if yes please guide me through it.

Django many-to-one relation with 3 tables

I dont want any foreign keys directly in my users table, and by default, when I add a foreing key field in my custom User model, Django generate 2 tabels like this:
When I add a many-to-many field in my Company model I get the 3 desired tables but it's made possible for the same user be in two different companys.
class Company(models.Model):
class Meta:
verbose_name = 'Company'
verbose_name_plural = 'Companys'
ordering = ['name']
db_table = 'companys'
id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True, verbose_name='ID Empresa')
name = models.CharField(max_length=100, verbose_name='Nome')
users = models.ManyToManyField(User, related_name='company', verbose_name='Users')
def __str__(self):
return self.name
I want Django to generate an additional table with only the Foreing Keys of the two models but keep the behevior of a many-to-one relationship between the two. like this:
you can make your third table by using a separate model
class Company(models.Model):
class Meta:
verbose_name = 'Company'
verbose_name_plural = 'Companys'
ordering = ['name']
db_table = 'companys'
id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True, verbose_name='ID Empresa')
name = models.CharField(max_length=100, verbose_name='Nome')
def __str__(self):
return self.name
class UserCompanyRelationModel(models.Model):
class Meta:
db_table = 'usr_comp'
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)

How to create a view for a nested serializer with foreign keys in django rest framework?

I got this code, but I can't find a way to create a view that retrieve the allergies a patient has.
class Patient(models.Model):
user = models.OneToOneField(User, related_name='patient', on_delete=models.CASCADE)
id_type = models.CharField(max_length=300)
id_number = models.CharField(max_length=300)
creation_date = models.DateField(default=datetime.date.today)
class Allergie(models.Model):
name = models.CharField(max_length=300, default="X")
class PatientAllergies(models.Model):
patient = models.ForeignKey(Patient, related_name="patient_allergies", on_delete=models.CASCADE)
allergie = models.ForeignKey(Allergie, on_delete=models.CASCADE, null=True)
professional_contract = models.ForeignKey(ProfessionalContract, null=True ,on_delete=models.CASCADE)
You can span a ManyToManyField relation over your PatientAllergies model that acts as a junction table:
class Patient(models.Model):
user = models.OneToOneField(User, related_name='patient', on_delete=models.CASCADE)
id_type = models.CharField(max_length=300)
id_number = models.CharField(max_length=300)
creation_date = models.DateField(auto_now_add=True)
allergies = models.ManyToManyField(
'Allergie',
through='PatientAllergies'
)
# …
You can then for a Patient object p with:
p.allergies.all()
An alternative is to filter the Allergie objects with:
Allergie.objects.filter(patientallergies__patient=p)
or with the ManyToManyField:
Allergie.objects.filter(patient=p)

Django API ManyToMany on existing databse not working

at the moment I try to get recipes from my API. I have a Database with two tables one is with recipes and their ids but without the ingredients, the other table contains the ingredients and also the recipe id. Now I cant find a way that the API "combines" those. Maybe its because I added in my ingredient model to the recipe id the related name, but I had to do this because otherwise, this error occurred:
ERRORS:
recipes.Ingredients.recipeid: (fields.E303) Reverse query name for 'Ingredients.recipeid' clashes with field name 'Recipe.ingredients'.
HINT: Rename field 'Recipe.ingredients', or add/change a related_name argument to the definition for field 'Ingredients.recipeid'.
Models
from django.db import models
class Ingredients(models.Model):
ingredientid = models.AutoField(db_column='IngredientID', primary_key=True, blank=True)
recipeid = models.ForeignKey('Recipe', models.DO_NOTHING, db_column='recipeid', blank=True, null=True, related_name='+')
amount = models.CharField(blank=True, null=True, max_length=100)
unit = models.CharField(blank=True, null=True, max_length=100)
unit2 = models.CharField(blank=True, null=True, max_length=100)
ingredient = models.CharField(db_column='Ingredient', blank=True, null=True, max_length=255)
class Meta:
managed = False
db_table = 'Ingredients'
class Recipe(models.Model):
recipeid = models.AutoField(db_column='RecipeID', primary_key=True, blank=True) # Field name made lowercase.
title = models.CharField(db_column='Title', blank=True, null=True, max_length=255) # Field name made lowercase.
preperation = models.TextField(db_column='Preperation', blank=True, null=True) # Field name made lowercase.
images = models.CharField(db_column='Images', blank=True, null=True, max_length=255) # Field name made lowercase.
#ingredients = models.ManyToManyField(Ingredients)
ingredients = models.ManyToManyField(Ingredients, related_name='recipes')
class Meta:
managed = True
db_table = 'Recipes'
When there is no issue it has to be in the serializer or in the view.
Serializer
class IngredientsSerializer(serializers.ModelSerializer):
# ingredients = serializers.CharField(source='ingredients__ingredients')
class Meta:
model = Ingredients
fields = ['ingredient','recipeid']
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients = IngredientsSerializer(many=True)
class Meta:
model = Recipe
fields = ['title','ingredients']
View
class FullRecipesView(generics.ListCreateAPIView):
serializer_class = FullRecipeSerializer
permission_classes = [
permissions.AllowAny
]
queryset = Recipe.objects.all()
This is at the moment my output
But I want e.g. the recipe with id 0 and all the ingredients which have also recipe id 0.
I really hope that you can help me. Thank you so much!
Rename ingredients to some other name in FullRecipeSerializer. It conflicts with ingredients in Recipe model. This should solve your issue. For example
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients_recipe = IngredientsSerializer(many=True, source= 'ingredientid')
class Meta:
model = Recipe
fields = ['title','ingredients_recipe']

Query using Joins in Django

class Students(models.Model):
id = models.BigAutoField(primary_key=True)
admission_no = models.CharField(max_length=255)
roll_no = models.CharField(unique=True, max_length=50, blank=True, null=True)
academic_id = models.BigIntegerField()
course_parent_id = models.BigIntegerField()
course_id = models.BigIntegerField()
first_name = models.CharField(max_length=20)
middle_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
user_id = models.BigIntegerField()
date_of_birth = models.DateField(blank=True, null=True)
date_of_join = models.DateField(blank=True, null=True)
class Courses(models.Model):
id = models.BigAutoField(primary_key=True)
parent_id = models.IntegerField()
course_title = models.CharField(max_length=50)
slug = models.CharField(unique=True, max_length=50)
tenant_user = models.ForeignKey('Users', models.DO_NOTHING, default='')
course_code = models.CharField(max_length=20)
course_dueration = models.IntegerField()
grade_system = models.CharField(max_length=10)
is_having_semister = models.IntegerField()
is_having_elective_subjects = models.IntegerField()
description = models.TextField()
status = models.CharField(max_length=8)
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'courses'
def __unicode__(self):
return self.course_title
class StudentProfileSerializer(ModelSerializer):
class Meta:
model = Students
depth = 0
fields = '__all__'
The first two tables/class contains the course and student table and the third contains the serializer. Can anyone please help how to query using the joins in django. I need to fetch the course_title from Courses table and first_name from Students table.
IMHO, you should review your models; course_id in Students should be a course=models.ForeignKey('Courses', ...); this way you can refer to the course title using dot notation;
student=Student.objects.filter(pk=...)
to refer to your required fields:
student.last_name, student.course.course_title
Besides, if I understood your models, you could get some incongruence... what if the value stored in course_parent_id in Students model is different from the value stored in parent_id in Courses model? maybe the first one is redundant.
To query a field from a related object use a double underscore. So you could do
Student.objects.filter(**kwargs).values('first_name', 'last_name', 'course__course_name')

Categories