Adding one to many relationship in Django models - python

I have two models in my Django-REST application.
a ProjectRequest and a ContactRequest
I want to make it so, each Projectrequest contains a list of the refered Contactrequests.
class ProjectRequest(models.Model):
project_name = models.CharField(max_length=50)
company_name = models.CharField(max_length=50)
#make array of technologiestechnologies = models.ArrayField(base_field=) (blank=True)
project_description = models.CharField(max_length=200)
project_type = models.CharField(max_length=30)
budget_estimation = models.IntegerField(
default=1000,
validators=[
MinValueValidator(1800),
MaxValueValidator(5000000)
])
#time_estimation = models.DateTimeField(default=None, blank=True, null=True)
class ContactRequest(models.Model):
topic = models.CharField(max_length=30)
description = models.CharField(max_length=200)
time = models.CharField(max_length=15)
project_request = models.ForeignKey(ProjectRequest,
on_delete=models.CASCADE)
so far I have established a relationship, with a foreign key, which works fine as of now. However I want to extends the functionality, so, that the ProjectRequest contains a list of all the projectrequest. I have tried with several different fields, without any luck, and the documentation I can only find fields for ManyToMany and OneToOne. How can this be achieved?

There are many ways to achive what you want. For that, lets add a reverse relation in model named contact_requests:
project_request = models.ForeignKey(ProjectRequest, on_delete=models.CASCADE, related_name="contact_requests")
Now you can use PrimaryKeyRelatedField to show Primary Keys of the ContactRequest attached to each ProjectRequest.
class ProjectRequestSerializer(serializers.ModelSerializer):
contact_requests = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = ProjectRequest
fields = ('contact_requests', 'company_name', ...) # other fields
Or if you want all the values of each contact_requests, then you can use nested relationship like this:
class ProjectRequestSerializer(serializers.ModelSerializer):
contact_requests = ContactRequestSerializer(many=True, read_only=True)
class Meta:
model = ProjectRequest
fields = ('contact_requests', 'company_name', ...) # and so on

You could add a property function to the ProjectRequest class that retruns all the ContactRequests that are related to that ProjectRequest like so...
class ProjectRequest(models.Model):
project_name = models.CharField(max_length=50)
company_name = models.CharField(max_length=50)
#make array of technologiestechnologies = models.ArrayField(base_field=) (blank=True)
project_description = models.CharField(max_length=200)
project_type = models.CharField(max_length=30)
budget_estimation = models.IntegerField(
default=1000,
validators=[
MinValueValidator(1800),
MaxValueValidator(5000000)
])
#time_estimation = models.DateTimeField(default=None, blank=True, null=True)
#property
def contact_requests(self):
return ContactRequest.objects.filter(project_request=self)
class ContactRequest(models.Model):
topic = models.CharField(max_length=30)
description = models.CharField(max_length=200)
time = models.CharField(max_length=15)
project_request = models.ForeignKey(ProjectRequest,
on_delete=models.CASCADE)

I had this problem too. This is how I solved it:
ContactRequest= models.ManyToManyField(ContactRequest,related_name="+")

Related

django getting all objects from select

I also need the field (commentGroupDesc) from the foreign keys objects.
models.py
class commentGroup (models.Model):
commentGroup = models.CharField(_("commentGroup"), primary_key=True, max_length=255)
commentGroupDesc = models.CharField(_("commentGroupDesc"),null=True, blank=True, max_length=255)
def __str__(self):
return str(self.commentGroup)
class Meta:
ordering = ['commentGroup']
class Comment (models.Model):
commentID = models.AutoField(_("commentID"),primary_key=True)
commentUser = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
commentGroup = models.ForeignKey(commentGroup, on_delete=models.CASCADE, null=True)
commentCI = models.ForeignKey(Servicenow, on_delete=models.CASCADE, null=True)
commentText = RichTextField(_("commentText"), null=True, blank=True)
commentTableUpdated = models.CharField(_("commentTableUpdated"), null=True, blank=True, max_length=25)
def __str__(self):
return str(self.commentGroup)
class Meta:
ordering = ['commentGroup']
views.py
comment = Comment.objects.get(pk=commentID)
Here I get the commentGroup fine but I also need commentGroupDesc to put into my form.
At first, it's not a good thing to name same your model field as model name which is commentGroup kindly change field name, and run migration commands.
You can simply use chaining to get commentGroupDesc, also it's better to use get_object_or_404() so:
comment = get_object_or_404(Comment,pk=commentID)
group_desc = comment.commentGroup.commentGroupDesc
Remember to change field and model name first.

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']

ForeignKey to abstract model

I have an abstract Product model, and I wanted it to be able to hold more than one image, so I decided to make another Image model and have a ForeignKey to Product, however I quickly realised that's not possible. The reason I decided to go for abstract base model is performance gains since every child model is in its own table. Having a different Image model for each subclass sounds bad to me, since there will be more than 20 subclasses.
class Product(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=50)
category = models.ForeignKey('Category', on_delete=models.CASCADE, blank=False)
class Meta:
abstract = True
class Book(Product):
author = models.CharField(max_length=50)
publisher = models.CharField(max_length=50)
class Shoes(Product):
colour = models.CharField(max_length=50)
size = models.CharField(max_length=50)
class Image(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
How can I overcome the issue?
You can use a ManyToManyField:
class Product(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=50)
category = models.ForeignKey('Category', on_delete=models.CASCADE, blank=False)
images = models.ManyToManyField(Image)
class Meta:
abstract = True
inserting data:
b1 = Book.objects.create(...) #can't include M2M yet
i1 = Image.objects.create(...)
i2 = Image.objects.create(...)
b1.images.add(i1, i2)
You can query the images like this:
books = Book.objects.all().prefetch_related('images')
images_for_book_1 = books[0].images.all()

Creating SubCategories with Django Models

I am trying to expand the relationships within my Django Models. I have a system where elements are stored within Categories. How do I structure my models.py so that each category is related to a subcategory?
Here is what my category model looks like:
class Category(models.Model):
site = models.ForeignKey(Site)
template_prefix = models.CharField(max_length=200, blank=True)
name = models.CharField(max_length=200)
slug = models.SlugField()
description = models.TextField(default='')
sortby_fields = models.CharField(max_length=200,
help_text=_(u'A comma separated list of field names that should show up as sorting options.'),
blank=True)
sort_order = models.PositiveIntegerField(default=0)
def __unicode__(self):
return self.name + u' Category'
class Meta:
verbose_name_plural = u'categories'
Thanks for any suggestions.
You can create a foreign key to itself:
class Category(models.Model):
...
parent_category = models.ForeignKey('self', null=True, blank=True)
Then you can assigning any existing Category instance as the parent_category of that instance. Then, if you wanted to find all of the subcategories of a given Category instance you would do something like:
subcategories = Category.objects.filter(
parent_category__id=target_category.id)
You can also try django-mptt. It has some additional features.

How to use dynamic foreignkey in Django?

I want to connect a single ForeignKey to two different models.
For example:
I have two models named Casts and Articles, and a third model, Faves, for favoriting either of the other models. How can I make the ForeignKey dynamic?
class Articles(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Casts(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Faves(models.Model):
post = models.ForeignKey(**---CASTS-OR-ARTICLES---**)
user = models.ForeignKey(User,unique=True)
Is this possible?
Here is how I do it:
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import fields
class Photo(models.Model):
picture = models.ImageField(null=True, upload_to='./images/')
caption = models.CharField(_("Optional caption"),max_length=100,null=True, blank=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = fields.GenericForeignKey('content_type', 'object_id')
class Article(models.Model):
....
images = fields.GenericRelation(Photo)
You would add something like
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = fields.GenericForeignKey('content_type', 'object_id')
to Faves
and
fields.GenericRelation(Faves)
to Article and Cast
contenttypes docs
Here's an approach. (Note that the models are singular, Django automatically pluralizes for you.)
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Cast(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
FAVE_CHOICES = (
('A','Article'),
('C','Cast'),
)
class Fave(models.Model):
type_of_fave = models.CharField( max_length=1, choices=FAVE_CHOICES )
cast = models.ForeignKey(Casts,null=True)
article= models.ForeigKey(Articles,null=True)
user = models.ForeignKey(User,unique=True)
This rarely presents profound problems. It may require some clever class methods, depending on your use cases.

Categories