One-To-Many models and Django Admin - python

I have the following models:
#models.py
class Section(models.Model):
name = models.CharField(max_length=20)
class Tags(models.Model):
parent = models.ForeignKey(Section)
name = models.CharField(max_length=255, blank=True)
class Article(TimeStampedMode):
...
tag = models.ForeignKey(Tags)
In Django admin, tag shows up as a HTML <select multiple>.
What I'm trying to do is:
A Section could have many Tags, and from Article I could pick a Tags from Section.
Also, it needs to be able to get a Article's Section(via tags.parent?).
Currently this works. But, instead of <select multiple>, Tags shows up as a <input> instead of a <select multiple>.
What I want is for both Tags and Section appear as <select multiple>.
edit:
What I want is:

By using a foreign key to define the relationship, you're limiting the number of Tags an Article may have to 1. For an Article to have more than one Tag, you'll want to use a ManyToMany relationship.
Read more on many-to-many relationships with Django here: https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
The Django admin site will automatically use a select if you're using a foreign key relationship, or a multi-select if you're using a many-to-many relationship.
Here's what a many-to-many will look like from Article to Tags:
class Article(TimeStampedMode):
...
tag = models.ManyToManyField(Tags)

I don't understand your need correctly. But according to your image, you need Section and Tags are set One-To-Many field in Article.
#models.py
class Section(models.Model):
name = models.CharField(max_length=20)
class TagName(models.Model):
tag_name = models.CharField(max_length=255, blank=True)
class Tags(models.Model):
parent = models.ForeignKey(Section)
name = models.ForeignKey(TagName)
class Article(TimeStampedMode):
...
tag = models.ForeignKey(Tags)
I think this method is more useful and matching with your need.
screenshot of the given model code:
this is Article page
go into tag and you can see select multiple for both fields
Thank you

Related

Iterate over ManyToMany field Django

I am having some problems with iterating over a ManyToMany field.
I want to have a Post and Tag model, and have the Post model extend the Tag model in the form of a ManyToMany relation.
Below are both my Tag and Post models.
class Tag(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return f"{self.name}"
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
content = RichTextField()
timestamp = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True,default="",max_length=1000)
tag = models.ManyToManyField(Tag,related_name='tags',blank=True)
# .... other non related functions
However, when I am in the Django shell, I can't seem to loop over these tags, despite the object having tags associated to it.
For example, I would do post1 = Post.objects.all()[0], and then post1.tag.name.all(), however it would give me an error saying "AttributeError: 'NoneType' object has no attribute 'all'
Everything else I have tried failed. What can I fix to solve the issue?
Thank you in advance
You are suppose to iterate through tags object like this
for tag in post1.tag.all():
print(tag.name)
It is very simple to iterate over ManyToManyField
for tag in post1.tag.all():
print(tag.name)
Other than iteration, I have some other suggestions. Like
tag will have many tags so naming it tags is more suitable. Secondly related_name is The name to use for the relation from the related object back to this one So in your case it should be posts instead of tags
So it will look like
tags = models.ManyToManyField(Tag, related_name='posts', blank=True)
Now you can access posts from any specific tag using this related_name. For example, If you have tag
tag1 = Tag.objects.all()[0]
Now you can get all posts with this tag using following line
tag1_posts = tag1.posts.all()

Django Models - One to Many or Many o Many

In Django there are no One-to-Many relationships, there are just Many-to-One. In cases where defining Foreign Key on the child table is odd, should we go for Many-to-Many?
For example:
Book has many pages. If we define foreign key on the Page model, then the page has one book which is not an intuitive thing to do (or say).
OPTION 1:
class Book(models.Model):
name = models.CharField(max_length=100)
date_published = models.DateTimeField(default=timezone.now)
class Page(models.Model):
page_number = models.IntegerField()
page_text = RichTextField()
book = models.ForeignKey(Book, on_delete=models.CASCADE)
OPTION 2
class Book(models.Model):
name = models.CharField(max_length=100)
date_published = models.DateTimeField(default=timezone.now)
pages = models.ManytoMany(Page)
class Page(models.Model):
page_number = models.IntegerField()
page_text = RichTextField()
In option2 I can access the pages of the book by book.pages.
In option 1 I don't know how to access the pages, maybe book.pages_set.objects.all() which is not pretty.
I asked a fellow programmer and he said just use Many-to-Many. I understand what each approach means and I also understand the difference between the two as to what's happening in the database. My question is what is a better/standard approach.
I prefare the first option because many books doesn't have common page and its contains.
So, using first option you can access book pages using following queryset
pages = book.page_set.all()
Here, you can also use related_name parameter in foreignkey field as:
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name="pages")
then book pages can be fetched using
pages = book.pages.all()
I would like to use first example. As Books do not have common pages. For connecting Book to Page, you have to use backward relationship. In this relationships, _set method is used. All the model name & filed name must be small letter although they are in capital letter.
m=book.page_set.all()
Now you can use all attribute of Page from Book using m.
For more about reverse or backward relationship visit here
In your view you pass the id of the Book and you use it in your query to filter the pages they are linked to it.
for example:
def show_pages(request, book_id):
pages = Pages.objects.filter(book=book_id)

Is there a way to get all ManyToMany related objects in DRF

I have Tags in my application and it's possible to Tag different things like News, Events...
News and Events have a ManyToMany relation to Tags. Is it possible to get every object where the Tag is used?
My Models (shortened) look like this:
Tag Model
class Tag(models.Model):
title = models.CharField(max_length=35)
News Model
class News(models.Model):
title = models.CharField(max_length=75)
tag = models.ManyToManyField(Tag, related_name="news")
Event Model
class Event(models.Model):
title = models.CharField(max_length=75)
tag = models.ManyToManyField(Tag, related_name="event")
I know that I can get all News that have the Tags assigned by
tag = self.get_object()
tag.news.all()
But is it possible to get all News, Events... without 10 requests? I'm looking for something like tag.all.all()
try this
tag.news.all() | tag.event.all()
"news" and "event" are accessible due to reverse relationship here which are defined in their respective model fields with the keyword "related_name".
note that this may give duplicate tags as it is a union between the two.
for distinct tags,
(tag.news.all() | tag.event.all()).distinct()

django-taggit obtain tags string from form

I trying to use django-taggit as a tag model.
model.py
class Product(models.Model):
product_no = models.IntegerField(primary_key=True)
...
tags = TaggableManager(blank=True)
views.py
def action(request):
product = Product()
user = User.objects.get(id=request.user.id)
product.seller_username = user
...
product.save()
tag_list = taggit.utils._parse_tags(request.POST['tags'])
product.tags.add(*tag_list)
When I call method product.tags.add(), I'm getting an error say
Product objects need to have a primary key value before you can access
their tags
Many solutions I find inform me to put product.save() before product.tags.add() to make pk available before access many-to-many field.
I've try it and still the error.
Note: the save() method work properly. It create new object in Product list and can be see in admin interface.
It seem that I have to change
product_no = models.IntegerField(primary_key=True)
to
product_no = models.AutoField(primary_key=True)
and it's fixed.

Reverse Relation Search Django Admin Interface

Is it possible to do a reverse relation search on the Django Admin interface?
My Django app database schema consists of the following models:
class Tag(models.Model):
title = models.CharField(max_length=50)
class Publication(models.Model):
title = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag, blank=True, related_name="publications")
I have added a search field for looking up tags by title in my admin.py file by doing:
class TagAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ('title',)
Thus, when I type a tag title into the search field on the django admin interface, a list of matching tag titles comes up. Now I'd like to make it so that if I type a tag title into the search field, matching publications come up.
In other words, I'm imagining something like:
class TagAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ('publications',)
Which of course doesn't work... but that's the idea...
Is this even possible? And/or am I even going about this the right way? If so, could someone suggest a way to do this or a resource? If you are kind enough to do so, please keep in mind that I am very much a beginner. Thanks.
You shouldn't try to do this using an admin class registered to your Tag model. Instead, set up an admin class for Publication and set its search_fields:
class PublicationAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ('tags__title',)

Categories

Resources