I am defining a set of models, which have references to each other. They are a model for a documentation app, which is as follows
class Document(models.Model):
text = models.TextField()
class Chapter(models.Model):
doc = models.ForeignKey('Document')
chapter = models.IntegerField()
I want the integer field to be unique per document, but am not sure how to do so. I know there is a unique parameter for each field, but it seems like it is unique for the entire table, which is not what I want.
You can use unique together in your model is meta:
class Chapter(models.Model):
doc = models.ForeignKey('Document')
chapter = models.IntegerField()
class Meta:
unique_together = (("doc", "chapter"),)
Here's the doc
(Django 3.1) edit: Using unique_together is now discouraged by the docs and may be deprecated in the future, as per the docs. Use UniqueConstraint instead:
class Chapter(models.Model):
doc = models.ForeignKey('Document')
chapter = models.IntegerField()
class Meta:
constraints = [
models.UniqueConstraint(
fields=['doc', 'chapter'],
name='unique chapter'
)
]
Related
I've two models as below.
class Category(models.Model):
title = models.CharField(max_length=55)
class Meta:
verbose_name = 'Food Category'
verbose_name_plural = 'Food Categories'
def __str__(self):
return self.title
class FoodItem(TimeStampWithCreator):
CATEGORY_CHOICES = (
('takeway', 'Takeaway'),
('dine_in', 'Dine In'),
('function', 'Function'),
)
type_menu_select = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default='takeway')
category = models.ForeignKey(FoodCategory, on_delete=models.CASCADE)
i want to filter all the categories containing takeaway, I've no idea how to achieve this
You've included category choices in your FoodItem model but the model also has a ForeignKey to a Category model, this isn't needed if the only category objects you have are those three choices (the category field must refer to one of those anyway as it's the ForeignKey). To filter the items by category you would need to use a queryset filter.
https://docs.djangoproject.com/en/3.0/topics/db/queries/#retrieving-specific-objects-with-filters
FoodItem.objects.filter(category=YourCategory)
This is usually the kind of thing I'd like to test in the shell as I don't do it very often. If what you want is actually all Category with a FoodItem that have type_menu_select set to 'takeway' then the following should work (but I haven't tested it):
Category.objects.filter(fooditem__type_menu_select='takeway')
This is using the "reverse" relationship on the ForeignKey and there's more information in the Django docs (search for 'reverse').
I tried to check another topics, but didn't found a solution...
I have a many-to-many model, that have intermediate model with another field additional_field inside.
class BoardField(models.Model):
title = models.CharField(max_length=500, default='')
class Article(models.Model):
title = models.CharField(max_length=500, default='')
fields = models.ManyToManyField(BoardField, through='ArticleField', through_fields=('article', 'board_field'))
class ArticleField(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='task')
board_field = models.ForeignKey(BoardField, on_delete=models.CASCADE)
additional_field = models.CharField(max_length=200, blank=True, null=True)
I want serialize Article with structure:
[
"title":"Title",
"fields":[
{
"board_field": {
"title":"Title"
},
"additional_field":"Additional info"
}
]
]
So, I wrote serializer:
class BoardFieldSrl(serializers.ModelSerializer):
class Meta:
model = BoardField
fields = (
'title',
)
class ArticleFieldSrl(serializers.ModelSerializer):
board_field = BoardFieldSrl()
class Meta:
model = ArticleField
fields = (
'board_field',
'additional_field',
)
class ArticleListSrl(serializers.ModelSerializer):
fields = ArticleFieldSrl(many=True)
class Meta:
model = Article
fields = (
'title',
'fields',
)
But I always got an error:
Got AttributeError when attempting to get a value for field `board_field` on serializer `ArticleFieldSrl`.
The serializer field might be named incorrectly and not match any attribute or key on the `BoardField` instance.
Original exception text was: 'BoardField' object has no attribute 'board_field'.
I made another several examples, but they doesn't gave my result, that I need... My maximum - I got BoardField with levels, but without intermediate model...
Can you help me with serializer, that return structure, that I mentioned above? It must include intermediate model ArticleField and nested BoardField.
Try fields = ArticleFieldSrl(source='articlefield_set', many=True)
You didn't specified a related_name at M2M field so the default naming is applied which is 'Intermediate model name'_set and if you want to use the fields on M2M relation you have to tell the serializer where to look for.
EDIT:
Camel removed from articlefield_set, model name is always converted to lower case
I am trying to implement a serializer that returns a parent record with its children embedded in the response json object.
My model for the parent and child are both based on database views:
class ProductContributorView(models.Model): # its a model of a view
id = models.IntegerField(primary_key=True)
product_id = models.ForeignKey('ProductTitleView', on_delete=models.DO_NOTHING, related_name='contributors')
sequenceNumber = models.IntegerField()
name = models.CharField(max_length=180)
role = models.CharField(max_length=8, null=True)
description = models.CharField(max_length=1408)
class Meta:
managed = False
ordering = ['sequenceNumber',]
class ProductTitleView(models.Model):
id = models.IntegerField(primary_key=True)
isbn = models.CharField(max_length=80)
titleText = models.CharField(max_length=300)
class Meta:
managed = False
ordering = ['titleText', 'isbn',]
Here are the serializers:
class ProductContributorViewSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ProductContributorView
fields = ('id', 'product_id', 'sequenceNumber', 'name', 'role', 'description')
def create(self, validated_data):
contributor = ProductContributorView.objects.create(
id=validated_data['id'],
product_id=validated_data['product_id'],
sequenceNumber=validated_data['sequenceNumber'],
name=validated_data['name'],
role=validated_data['role'],
description=validated_data['description'])
return contributor
class ProductTitleViewSerializer(serializers.HyperlinkedModelSerializer):
contributors = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = ProductTitleView
fields = ('id', 'isbn', 'titleText', 'contributors')
Here are the views:
class ProductTitleViewList(generics.ListAPIView):
queryset = ProductTitleView.objects.all()
serializer_class = ProductTitleViewSerializer
class ProductContributorViewList(generics.ListAPIView):
queryset = ProductContributorView.objects.all()
serializer_class = ProductContributorViewSerializer
The basic idea is to have the contributors - author, illustrator, etc - returned with the book title based on the FK in the ProductContributorView view matching the id in the ProductTitleView.
When I run this, however, I get the following error:
1054, "Unknown column 'jester_productcontributorview.product_id_id' in 'field list'"
I didn't specify product_id_id in the field list, and I've also tried referring to the field as just product in the field list, but it still repeats the _id_id suffix. Hoping someone will point me to documentation where the FK naming conventions are explained or tell me what to change in the field list. Thanks!
You may just want to try renaming that product_id ForeignKey to just product.
This hints to why it may be broken, I suspect it's breaking somewhere in the serializers inspection of your models regarding the naming of the product_id field on the model.
When you define a ForeignKey on a model there are two properties available for that field. One is the property you define, the ForeignKey object, and you should use this to get the related model. Behind the scenes Django also creates another property which appends _id to the the foreign key's name, this property represents the IntegerField on the database which stores the relation. If you were to view the table in psql you will see the _id columns (and in your case, _id_id).
I have the following Model:
class CodeSynonyms(models.Model):
code = models.ForeignKey(Codes, on_delete=models.CASCADE)
websites = models.ManyToManyField(Websites)
synonym = models.Charfield(max_length=10)
The idea is that Websites use the Synonyms for specific Codes. One Website can't have few Synonyms for a Code; various Websites can share the same Synonym for specific Code. The following won't work:
class Meta:
unique together = ('code', 'websites')
" 'unique_together' refers to a ManyToManyField 'websites', but ManyToManyFields are not permitted in 'unique_together' "
Is there a way to solve this keeping the M2M relation? It would be handy to have it
you can use through in ManyToManyFieldand connect your many to many relations through custom intermediate table. then add unique_together there:
class CodeSynonyms(models.Model):
# add through field
websites = models.ManyToManyField(Websites, through='WebsiteCode')
synonym = models.Charfield(max_length=10)
class WebsiteCode(models.Model):
code_synonym = models.ForeignKey(CodeSynonyms, on_delete=models.CASCADE)
website = models.ForeignKey(Websites, on_delete=models.CASCADE)
code = models.ForeignKey(Codes, on_delete=models.CASCADE)
class Meta:
unique together = ('code', 'website')
Here's two simple models to use as an example:
class Author(models.Model):
name = models.CharField(blank=True, max_length=50)
age = models.IntegerField(null=True, )
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
date = models.DateField()
Now what I'd like to do, is create a view for Book that pulls in one of the values from Author using the Django Rest Framework. Here's an example ModelSerializer:
class BookMetaSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('title','date','author__name',)
The trouble is that one can't access the fields of a foriegn key in the DRF like I gave above author__name. I haven't been able to figure out how to do this based on the documentation. All help is appreciated, thanks!
You can define author_name field with source argument to get the name of an author.
From the DRF docs on source argument:
The name of the attribute that will be used to populate the field. May
be a method that only takes a self argument, such as
URLField('get_absolute_url'), or may use dotted notation to traverse
attributes, such as EmailField(source='user.email').
Final Code:
class BookMetaSerializer(serializers.ModelSerializer):
# use dotted notation to traverse to 'name' attribute
author_name = serializers.CharField(source='author.name', read_only=True)
class Meta:
model = Book
fields = ('title','date','author_name',)