I need some input about referring an Autofield into another model.
I tried making a foreign key, but I am not sure if the syntax is right
I have a main model class with id as Autofield
class Metadataform(models.Model):
id = models.AutoField(primary_key=True)
Authors_Name = models.CharField(max_length=500, blank=True, null=True)
Then I have a upload class
(I basically want to fetch the same id from the main model into the Meta_id in the uploadmeta model)
class uploadmeta(models.Model):
Meta_id = models.ForeignKey('Metadataform',on_delete=models.CASCADE, null=True)
Authors_Name = models.CharField(max_length=500, blank=True, null=True)
tar_gif = models.FileField(upload_to='mnt/storage/DB-Data/')
def __str__(self):
return self.Meta_id
Your approach is indeed correct, although you do not need to add a primary key yourself. Django does that. Furthermore your code does not really follows the naming conventions.
You can implement this as:
class MetadataForm(models.Model):
author_name = models.CharField(max_length=500, blank=True, null=True)
class UploadMeta(models.Model):
metadata_form = models.ForeignKey('MetadataForm', on_delete=models.CASCADE, null=True)
tar_gif = models.FileField(upload_to='mnt/storage/DB-Data/')
Furthermore it might not make much sense to set blank=True. This means that by default that field will not show up in forms. null=True not be necessary as well, since that means you can add None (in the database NULL) to that field.
The __str__ of a model typically includes some field value(s) of that model. Since by only using values from a ForeignKey relation, it means two or more UploadMetas that have different values, have the same textual representation if these refer to the same MetaDataForm?
It is not very clear to me eather why you defined a field named Authors_Name in the UploadMeta as well. If that is the same as the metadata_form's author_name, then you better do not include an extra one since that creates data duplication.
Perhaps it is better to make an Author model as well, and let MetadataForm refer through a ForeignKey to the author of that MetadataForm model.
Related
I am building a blog website and I am using Django rest framework
I want to fetch top 2 comments for a particular post along with their related data such as user details.
Now I have user details in two models
User
People
and the comments model is related to the user model using foreign key relationship
Models ->
Comments
class Comment(models.Model):
comment = models.TextField(null=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments_post')
user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='comments_user')
The People model is also connected to the user model with a foreign key relationship
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,related_name='people')
Name = models.CharField(max_length=255,null=True)
following = models.ManyToManyField(to=User, related_name='following', blank=True)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
for fetching the comments I am using rest-framework and the serializers look like this
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=255)
class peopleSerializer(serializers.Serializer):
Name = serializers.CharField(max_length=255)
class commentsSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
comment = serializers.CharField(max_length=255)
Created_date = serializers.DateTimeField()
user = UserSerializer()
people = peopleSerializer()
The query to fetch the comments look like this ->
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(post_id=post_id).select_related('user').prefetch_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
I am getting this error ->
Got AttributeError when attempting to get a value for field `people` on serializer `commentsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Comment` instance. Original exception text was: 'Comment' object has no attribute 'people'.
Unable to find a way out.
The source is user.people, not people, so:
class commentsSerializer(serializers.Serializer):
# …
people = peopleSerializer(source='user.people')
In the .select_related(…) [Django-doc] to can specify user__people: this will imply selecting user and will fetch the data in the same query, not in an extra query as is the case for .prefetch_related(…) [Django-doc]:
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(
post_id=post_id
).select_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
Note: normally a Django model is given a singular name, so Person instead of People.
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.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: created_date instead of Created_date.
Below models.py to build a blog in wagtail site is from this post.
class BlogPage(Page):
description = models.CharField(max_length=255, blank=True,)
content_panels = Page.content_panels + [FieldPanel("description", classname="full")]
class PostPage(Page):
header_image = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
tags = ClusterTaggableManager(through="blog.PostPageTag", blank=True)
content_panels = Page.content_panels + [
ImageChooserPanel("header_image"),
InlinePanel("categories", label="category"),
FieldPanel("tags"),
]
class PostPageBlogCategory(models.Model):
page = ParentalKey(
"blog.PostPage", on_delete=models.CASCADE, related_name="categories"
)
blog_category = models.ForeignKey(
"blog.BlogCategory", on_delete=models.CASCADE, related_name="post_pages"
)
panels = [
SnippetChooserPanel("blog_category"),
]
class Meta:
unique_together = ("page", "blog_category")
#register_snippet
class BlogCategory(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=80)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
def __str__(self):
return self.name
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
class PostPageTag(TaggedItemBase):
content_object = ParentalKey("PostPage", related_name="post_tags")
#register_snippet
class Tag(TaggitTag):
class Meta:
proxy = True
I am wondering, what are the major reasons to introduce extra Intermediary model (class PostPageBlogCategory(models.Model): & class PostPageTag(TaggedItemBase):) to link PostPage to Category & Tag?
Why not just simply use ParentalForeignkey or ParentalManyToManyKey ?
The short answer is that Django's ManyToManyField has some limitations in how the relationship needs to be built when models on either end to not yet exist, adding an 'intermediary model' helps to work around this.
Longer Answer
As with anything in software, there are multiple ways to do something and each has its own pros & cons. Django's built in field is simple and lets you do lots of powerful things to represent relational data but that simplicity comes with some reduced flexibility in how these relationships are managed.
One of the main goals of the Wagtail CMS Admin interface is the ability to work as though the data has been created (including relationships) before actually clicking 'save'. While this may seem simple at first glance, getting to that point requires a bit of nuance under the hood once you start to consider relational data.
Wagtail comes built in with a very powerful library called django-modelcluster which has been purpose built for many of the cases where you want to work with relational data without having all the bits in the DB first.
Each Wagtail Page actually inherits the modelcluster.models.ClusterableModel, which is why some of the features in the blog post seem to work in the editor, even when the DB entries have not yet been saved.
On the blog post you linked, there is a section towards the end with the heading 'ParentalKey' that further explains this nuance and how just using Django's basic approach has some draw backs.
On the Django docs for many-to-many relationships, have a read through and note that each individual model instance must be in the database first and only then can you 'link' the two instances with a second update on each.
I have a main table
Slideshow
then a site specific table that captures a few extra details for that site.
Site1_Slideshow
In a web app (specific to a site) i want a single model i.e. Slideshow that combines the 2 tables above.
Currently i have the code below, but i dont think this is correct. I cant do things like
s = Slideshow.objects.get(slideshowId=1) as Slideshows only has the properties featurecategory and slideshow. So how can i have an model called Slideshow that is composed of these 2 tables but looks like it was a single db table.
class SlideshowAbstract(models.Model):
slideshowid = models.IntegerField(primary_key=True, db_column=u'SlideshowId') # Field name made lowercase.
headline = models.TextField(db_column=u'Headline') # Field name made lowercase.
class Meta:
db_table = u'Slideshow'
class Slideshow(models.Model):
slideshow = models.OneToOneField(SlideshowAbstract, primary_key=True,db_column=u'SlideshowId')
def __unicode__(self):
return self.slideshow.headline
class Meta:
db_table = u'Site1_Slideshow'
Think i found the solution.
On the Site1_Slideshow you need to add a column for django to use, that i presume is always the same as primary key value.
Its name is SlideshowAbstract_ptr_id
Once that is added you can change the Slideshow model to be
class Slideshow(SlideshowAbstract):
featureCategory = models.ForeignKey(Featurecategory,db_column=u'FeatureCategoryId')
def __unicode__(self):
return self.headline
class Meta:
db_table = u'Site1_Slideshow'
So doable but not the nicest if you are not doing "model first" and already have the schema. Would be good to be able to override the name of the _ptr_id column.
I did try adding the following to Slideshow too see if i could map this ptr col to the primary key
slideshowabstract_ptr_id = models.IntegerField(primary_key=True, db_column=u'SlideshowId')
but no cigar.
I havent tested inserts either but ...objects.all() works
Hi I have a lot of users in my system who are classified into different types. I want to store the address details of all those users. For instance the user could be a student, a school or a franchisee. All the users here could have an address information associated with them.
from django.db import models
from django.contrib.auth.Models import User
class Address(models.Model):
user = models.OneToOneField(User)
address = models.TextField()
class Student(models.Model):
user_id = models.ForeignKey(User)
address = models.ForeignKey(Address)
class School(models.Model):
user_id = models.ForeignKey(User)
address = models.ForeignKey(Address)
contact_person_name = models.CharField(max_length=50)
In this scenario there are 2 references to the User model - one through user_id and another through address.user though they should be referring to the same instance. Is it a bad practice to have duplicate references?
I thought of leaving out the 'user' foreignkey in Address, but I think that the address can't exist without a user. How to better model this?
As you already mentioned in question duplication of same field in
a model is not a good Idea.
If these are your actual models, I would suggest you using abstract
models:
from django.db import models
from django.contrib.auth.Models import User
class Profile(models.Model):
user = models.OneToOneField(User, related_name="%(app_label)s_%(class)s_related")
address = models.TextField()
class Meta:
abstract = True
class Student(Profile):
pass
class School(Profile):
contact_person_name = models.CharField(max_length=50)
This will generate two tables: students, schools with fields
user, address and user, address, contact_person_name
respectively.
I have a course catalogue and am trying to include pre-requisits.
A course has 0 to n pre-requisits and a course can be the pre-quesit for 0 to n courses.
The course class is as follows
class Course(models.Model):
class Meta:
ordering = ['course_code', 'title']
course_id = models.AutoField(primary_key=True)
course_code = models.SlugField(max_length=20, null=False, blank=False)
....
....
class Pre_requisit(models.Model)
course = models.ForeignKey(Course, course_id')
pre_req = ???????
I have tried the pre_req field as a ForeginKey and MamyToManyField but cant find a solution.
Django will not allow 2 ForeignKeys from Pre_requisit class to the Course class.
With the ManyToMany field evn through another table I still get errors.
Can anyone let me know how to acheive this relationship.
I wish to ensure the pre-requisit course exists and be able to link to it so it can be displayed.
Many thanks.
class Course(models.Model):
....
pre_req = models.ManyToManyField("self")
read more at http://docs.djangoproject.com/en/dev/ref/models/fields/#manytomanyfield
If you wish to store extra info you can specify a "through" table also ( info at http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany) such as hard pre-requisite or recommended etc.