Delete entry from intermediary model if m2m changed - python

I've got a question. I want to delete the record in 'through' model, while editing Competition model in Django Admin. It is about editing m2m field 'competition_field'. Example: Competition with fields('Height', 'Width), and I will remove 'width' from m2m, and nothing will change in model 'FieldValues' I have tried everything I know, but without some succes.
This is my models.py
class Fields(models.Model):
field_name = models.CharField(max_length=100, unique=True)
class Competitions(models.Model):
competition_title = models.CharField(max_length=100, unique=True)
competition_field = models.ManyToManyField(Fields)
class Applications(models.Model):
application_applicant = models.ForeignKey(Applicant, on_delete=models.CASCADE)
application_competition = models.ForeignKey(Competitions, on_delete=models.CASCADE,)
application_value = models.ManyToManyField(Fields, through='FieldsValues')
class FieldsValues(models.Model):
catch_fields = models.ForeignKey(Fields, on_delete=models.CASCADE)
application = models.ForeignKey(Applications, on_delete=models.CASCADE)
value = models.TextField(null=True, default=0)

Related

nullable field default value django models in inhertiance

I have a model of product and another model called Course that inherits the product but has a video field and an author Which is a ForeignKey with A teacher model which inherits from the user model which inherits from AbstractUser
Related Models:
class User(AbstractUser):
username = models.SlugField(default="", null=False, db_index=True, blank=True) # forced by django admin problems :(
password = models.CharField(max_length=255, null=True)
email = models.EmailField(max_length=255, unique=True)
group = models.ManyToManyField(Group)
is_teacher = models.BooleanField(default=False, null=False)
is_seller = models.BooleanField(default=False, null=False)
phoneNum = PhoneNumberField(null=False, unique=True, default='')
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username", "first_name", "last_name", "password"]
def save(self, *args, **kwargs):
self.username = slugify(self.first_name + self.last_name)
super().save(*args, **kwargs)
class Product(models.Model):
name = models.CharField(max_length=100, null=False, blank=True)
shoppers = models.ManyToManyField(User, related_name='shopper')
tumb = models.ImageField(upload_to=course_tumb_directory_path, null=False)
lastUpdate = models.DateTimeField(auto_now=True)
price = models.DecimalField(null=False, default=1000000, max_digits=7, decimal_places=0)
class Teacher(User):
TOPICS = [
("BP", "Basic Programming"),
("AP", "Advanced Programming"),
("CS", "Computer Science"),
("MS", "Mathematics"),
("CH", "Chemistry"),
("BL", "BioLogy"),
("PH", "physics"),
("EL", "Electronics"),
("RG", "Religious"),
("Or", "Other"),
]
topic = models.CharField(max_length=2, choices=TOPICS, default=TOPICS[-1][0])
class Course(Product):
video = models.FileField(upload_to=course_directory_path, null=True,
validators=[
FileExtensionValidator(allowed_extensions=['MOV', 'avi', 'mp4', 'webm', 'mkv'])])
author = models.ForeignKey(Teacher, on_delete=models.CASCADE, null=True)
when I'm trying to make migrations it says this:
It is impossible to add a non-nullable field 'product_ptr' to course without specifying a default. This is because the database needs something to populate existing rows.
I'm using PostgreSQL for my db, It didn't let me flush it so I Dropped it and ReCreated a new one
But I Still can't makemigrations
I tried these answers:
You are trying to add a non-nullable field 'new_field' to userprofile without a default
Django: You are trying to add a non-nullable field 'slug' to post without a default; we can't do that
It is impossible to add a non-nullable field 'id' to video without specifying a default
You are trying to add a non-nullable field 'id' to contact_info without a default
Error : "You are trying to add a non-nullable field"
I faced these kinds of errors before but one thing I couldn't figure out is that it isn't related to a field so I can't fix it
Python: 3.10.6
Django: 4.1
PostgreSQL: psql 14.6
OS: Ubuntu 22.04 (Not a VM)
I figured out that so many repetitive inheritances made this error not sure why but this solves it:
class BaseProduct(models.Model):
class Meta:
abstract = True
name = models.CharField(max_length=100, null=False, blank=True)
shoppers = models.ManyToManyField(User)
tumb = models.ImageField(upload_to=course_tumb_directory_path, null=False, blank=True)
lastUpdate = models.DateTimeField(auto_now=True)
price = models.DecimalField(null=False, default=1000000, max_digits=7, decimal_places=0)
class Product(BaseProduct):
count = models.DecimalField(null=False, default=1, max_digits=7, decimal_places=0)
class Course(BaseProduct):
video = models.FileField(upload_to=course_directory_path, null=True,
validators=[
FileExtensionValidator(allowed_extensions=['MOV', 'avi', 'mp4', 'webm', 'mkv'])])
author = models.ForeignKey(Teacher, on_delete=models.CASCADE, null=True, related_name='courses')
Inheriting from an abstract model instead of repetitive Inheritance

Django Model Instance as Template for Another Model that is populated by Models

I'm trying to create a workout tracking application where a user can:
Create an instance of an ExerciseTemplate model from a list of available Exercise models. I've created these as models so that the user can create custom Exercises in the future. There is also an ExerciseInstance which is to be used to track and modify the ExerciseTemplate created by the user, or someone else. I'm stripping the models of several unimportant fields for simplicity, but each contains the following:
class Exercise(models.Model):
# Basic Variables
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
def __str__(self):
return self.name
class ExerciseTemplate(models.Model):
# Foreign Models
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.SET_NULL,
null=True,
blank=True
)
recommended_sets = models.PositiveIntegerField(null=True, blank=True)
class ExerciseInstance(models.Model):
""" Foreign Models """
exercise_template = models.ForeignKey(
ExerciseTemplate,
on_delete=models.SET_NULL,
null=True,
blank=True
)
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
""" Fields """
weight = models.PositiveIntegerField(null=True, blank=True)
reps = models.PositiveIntegerField(null=True, blank=True)
Create a WorkoutInstance from a WorkoutTemplate. The WorkoutTemplate is made up of ExerciseTemplates. But the WorkoutInstance should be able to take the WorkoutTemplate and populate it with ExerciseInstances based on the ExerciseTemplates in the WorkoutTemplate. Here are the models that I have so far:
class WorkoutTemplate(models.Model):
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
date = models.DateTimeField(null=True, blank=True)
#category...
exercises = models.ManyToManyField(
Exercise,
through=ExerciseTemplate
)
def __str__(self):
return self.name
class WorkoutInstance(models.Model):
# Foreign Models
workout_template = models.ForeignKey(
'WorkoutTemplate',
on_delete=models.SET_NULL,
null=True,
blank=True
)
But this is where I get stuck. I'm not sure how to proceed. My intuition is one of the following:
I need to create a more simple architecture to do this. I'll take any suggestions.
I need to create a method within the model that solves this issue. If this is the case, I'm not sure what this would actually look like.
When you create a new WorkoutInstance object which references a given WorkoutTemplate object you get all its related ExerciseTemplate objects.
Then you just create a new object (row) for each ExerciseInstance in another model (table)
If you link your ExerciseInstance to WorkoutInstance via 'workout' you could do something like:
wt = WorkoutTemplate.get(id=1)
wi = WorkoutInstance.create(workout_template=wt)
for e in wt.exercisetemplate_set.all:
ExerciseInstance.create(exercise_template=e, workout=wi)
You can implent this in the method that creates the new WorkoutInstance or take a look at signals
https://docs.djangoproject.com/en/4.0/topics/db/optimization/#create-in-bulk

Django: Integrity error not null for ForeignKey id field

I have a model which contains ForeignKeys to a number of other models and find, for some reason, I am able to save one of these models absolutely fine, but another I receive a fault message saying:
IntegrityError: NOT NULL constraint failed: app_eofsr.flight_id
See below for my models.py:
# models.py
class Aircraft(models.Model):
esn = models.IntegerField()
acid = models.CharField(max_length=8)
engpos = models.IntegerField()
operator = models.CharField(max_length=5, default='---')
fleet = models.ForeignKey(Fleet, blank=True)
slug = models.SlugField(default=None, editable=False, max_length=50, unique=True)
class EoFSR(models.Model):
datetime_eofsr = models.DateTimeField(default=None)
flight_number = models.CharField(max_length=10)
city_from = models.CharField(max_length=4)
city_to = models.CharField(max_length=4)
and these both feed into this model:
# models.py
class Flight(models.Model):
flight_number = models.CharField(max_length=10)
city_from = models.CharField(max_length=4, default=None)
city_to = models.CharField(max_length=4, default=None)
datetime_start = models.DateTimeField(default=None)
aircraft = models.ForeignKey(Aircraft, on_delete=models.CASCADE)
eofsr = models.ForeignKey(EoFSR, on_delete=models.CASCADE)
The odd thing being, I can save an Aircraft record no problem at all, but cannot save an EoFSR record and receive the NOT NULL constraint error message. I've done the usual deleting of the migrations and even tried deleting the db.sqlite3, but still no luck! Any suggestions?
Try to set null=True in models You have ForeignKey() like:
aircraft = models.ForeignKey(Aircraft, null=True, on_delete=models.CASCADE)
, then makemigrations and migrate

Django Rest API ManyToMany gives nothing [] in API

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 = True
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!
From the doc of ForeignKey.related_name,
If you’d prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'.
So, change the related_name of Ingredients.recipeid field to
class Ingredients(models.Model):
# rest of the fields
recipeid = models.ForeignKey(
'Recipe',
models.DO_NOTHING,
db_column='recipeid',
blank=True,
null=True,
related_name="ingredients_ref" # Changed the related name
)
Then, migrate the database using python manage.py makemigrations and python manage.py migrate
Then, update your FullRecipeSerializer class as,
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients_forward = IngredientsSerializer(many=True, source="ingredients")
ingredients_backward = IngredientsSerializer(many=True, source="ingredients_ref")
class Meta:
model = Recipe
fields = ['title', 'ingredients_forward', 'ingredients_backward']
Note that, here I have added two fields named ingredients_forward and ingredients_backward because there existing two types of relationships between Recipe and Ingredients and I am not sure which one you are seeking.

Multiple user types and ratings in Django

I'm making a DRF backend with three user types: customer, personal trainer and gym owner. I want all the fields in the CustomUser class to apply to each user type. I also want some specific attributes to each user type (for example photo only for personal trainer and gym owner). Is this the right way to do it?
# models.py
class CustomUser(AbstractUser):
USER_TYPE_CHOICES = (
('customer'),
('personal_trainer'),
('gym_owner'),
)
user_type = models.CharField(blank=False, choices=USER_TYPE_CHOICES)
name = models.CharField(blank=False, max_length=255)
country = models.CharField(blank=False, max_length=255)
city = models.CharField(blank=False, max_length=255)
phone = models.CharField(blank=True, max_length=255)
ratings = models.ForeignKey(Rating, on_delete=models.CASCADE, null=True)
created_at = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class Customer(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
class PersonalTrainer(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
class GymOwner(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
I also have a ratings model. I want to be able to leave a rating as a customer to a personal trainer or a gym. Each rating will have a one to one relation with it's owner and it's target. I'm not sure however how I can make the relations..?
# models.py
class Rating(models.Model):
STAR_CONVERSION = (
(1, 'One Star'),
(2, 'Two Stars'),
(3, 'Three Stars'),
(4, 'Four Stars'),
(5, 'Five Stars'),
)
rating = models.PositiveSmallIntegerField(choices=STAR_CONVERSION)
caption = models.TextField(blank=True)
owner = models.OneToOneField(Customer, on_delete=models.CASCADE)
# I want a target as a one to one relation to either PersonalTrainer or GymOwner
target = models.OneToOneField(*either personal trainer or gym owner*)
You need to make both owner and target a ForeignKey rather than a OneToOneField. With the latter, you could only have one rating for every customer and one for every provider, which would be a bit restrictive :).
For PersonalTrainer and GymOwner, you need model inheritance. The parent model would either be an abstract class (with the data saved in the tables of the individual child models), or (preferably in this case as the fields of both models are the same) the data would be saved in the parent model (e.g. Provider), while the child models would be proxy models based on the parent model's data, but providing different behaviour where appropriate.
The Django docs have quite a lot to say about the different inheritance options.
class Provider(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
class PersonalTrainer(Provider):
class Meta:
proxy = True
class GymOwner(Provider):
class Meta:
proxy = True
class Rating(models.Model):
# ...
owner = models.ForeignKey(Customer, on_delete=models.CASCADE)
target = models.ForeignKey(Provider, on_delete=models.CASCADE)

Categories

Resources