Django : Displaying ManyToManyField in admin page as a Table - django

I have the following two models.
class Question(models.Model):
id = models.AutoField(primary_key=True)
question_body = models.TextField(blank=True)
question_response = models.TextField(blank=True)
def __str__(self):
return self.question_body
class SIGRound(models.Model):
sig = models.CharField(max_length=9, choices=SIG_CHOICES)
round_number = models.IntegerField(default=1)
round_description = models.CharField(max_length=500)
questions = models.ManyToManyField(Question)
I want to use the SIGRound from the admin page and since it is a many to many field, many answers on StackOverflow suggested to use filter_horizontal or inline
So I implemented both and checked out how they looked, filter_horizontal does not give me what I want and with inline it looks like this:
This is the code I am currently using:
class QuestionInline(admin.TabularInline):
model = SIGRound.questions.through
#admin.register(SIGRound)
class SIGRoundAdmin(admin.ModelAdmin):
inlines=[QuestionInline]
But I want to display this field as a table, similar to list_display in the normal admin page, how would I go about doing this?

Related

which is the better design of database for article Like function?

I'm using Django to develop a news website.Now I'm developing the like function in news detail page, this function is like that at the bottom of the news, there is a like button, once you click it the amount of like will add 1.
Now I have 2 choices to design the table of the database in django we call it model.I'm not sure which design is better.
First:just use one News model
class News(models.Model):
...code..
is_up = models.BooleanField(default=True)
up_count = models.IntegerField(default=0)
Once is_up ,up_count will add 1.
Sceond:use 2 models,News model and a separate Like model
class News(models.Model):
...code..
up_count = models.IntegerField(default=0)
class Like(models.Model):
"""
点赞表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE)
news = models.ForeignKey("News", null=True, on_delete=models.CASCADE)
is_up = models.BooleanField(default=True)
class Meta:
unique_together = [
('news', 'user'),
]
Any friend can tell which design is better ?
If you use the second one, you can know more information, depending on whether you need the data, or you can use ManyToManyField like this:
class News(models.Model):
...code..
likes = models.ManyToManyField('UserInfo')
This will record who liked this news.

How can I add a field to a many-to-many relationship in Django?

This is a question about how to add a field to a many-to-many relationship in Django.
I have a model LandingPage and a model Product. (Code below). In my project, LandingPages can have many Products listed on them and those same Products can appear on multiple different LandingPages.
Product is connected to LandingPage via a ManyToManyField.
My Goal:
I am trying to figure out how to add a field so that I can set the order (1 through 10) for Products on their associated LandingPages. Reminder, Product instances can appear on multiple LandingPages, so each instance will need to have a different order attribute.
Ideally, I'd like to expose this functionality via the built-in Django admin. Right now it shows the relationships table, but not the order field as it does not yet exist. (Screenshots/mockups below).
My Code:
models.py
class LandingPage(models.Model):
"""Stores a single LandingPage and metadata.
"""
name = models.CharField(max_length=200, help_text="The name is only used internally. It is not visible to the public.")
slug = models.SlugField(default="", editable=False, max_length=150, null=False, verbose_name="Slug", help_text="This is not editable.")
# Additional fields that I do not believe are relevant
class Product(models.Model):
"""Stores a single Product and metadata.
"""
name = models.CharField(max_length=200, help_text="Used internally. Not visible to the public.")
active = models.BooleanField(default=False, verbose_name="Product is Live on Landing Pages", help_text="Determines whether the product should be visible on the assocaited landing page or not.")
landing_page = models.ManyToManyField(
LandingPage,
verbose_name="Landing Page",
help_text="The landing page or pages that this product is assocaited with.",
)
# Additional fields that I do not believe are relevant
admin.py
# Inline configuration used by LandingPageAdmin
class ProductInline(admin.TabularInline):
"""Creates Inline table format for displaying Product data."""
model = Product.landing_page.through
extra = 0
class LandingPageAdmin(admin.ModelAdmin):
"""Specifies LandingPage data in Admin."""
readonly_fields=('slug',)
inlines = [ProductInline]
save_as = True
# Inline configuration used by Product Admin
class LandingPageInline(admin.TabularInline):
"""Creates Inline table format for displaying LandingPage data."""
model = LandingPage.product_set.through
extra = 0
class ProductAdmin(admin.ModelAdmin):
"""Specifies Product data in Admin."""
inlines = [LandingPageInline]
save_as = True
Mockups (for clarity):
Current State
Desired State
(I added the desired functionality in red for clarity. The order integers should be editable so that the order can be re-arranged.)
My Question
How can I accomplish this goal of adding an editable order field to this pre-existing relationship?
Should I manually add an order field to the product-landingpage join table that was automatically created by Django? If I do that, is there a way to have the Django admin show that added field?
Or should I go about it a totally different way?
Thank you in advance!
I found the answer to this.
The solution is create an intermediary model and connect it using "through". Example below:
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Official docs are here: https://docs.djangoproject.com/en/3.1/topics/db/models/#intermediary-manytomany
Others in my situation may find it useful to read this question/answer as it does a good job of explaining various solutions: Define an order for ManyToManyField with Django

Add new rows to related model on creation of parent model in Admin

I have models for adding products. The name of the products are in several languages, so I made a on-to-many raltion with a 'Name'-model.
This is my models
class Product(models.Model):
active = models.BooleanField()
class ProductName(models.Model):
productName = models.CharField(max_length=250)
product = models.ForeignKey('Product', on_delete=models.CASCADE)
language = models.ForeignKey('Language', on_delete=models.CASCADE)
def __str__(self):
return self.productName
class Language(models.Model):
language = models.CharField(max_length=55)
languageAbbreviation = models.CharField(max_length=10)
def __str__(self):
return self.language
Now in the admin page of mysite, I want to add product names on creation of a product.
I tried some misarable attempt with some thing I found about 'admin.TabularInline'. But I think that is wrong because nothing is working with that.
Any suggestion about how to solve this is much appreciated!
A model admin like this:
class ProductAdmin(admin.ModelAdmin):
class ProductNameInline(admin.TabularInline):
model = ProductNameInline
fields = ['productName', 'language']
model = Product
inlines = [ProductNameInline]
should provide you with a page that allows you set the name(s) of a product.
Make sure all the necessary static files for the javascript are available.

Tag system for Django

I am building a Quiz app where a user (Content Creator or Author) can create quizzes (choice based questions and their solutions) from a specific domain. These quiz can be attempted by other users (Consumers - not yet implemented).
To allow quiz consumers to be able to search questions based on specific domains of their interest (and to add granularity to the quiz content), I am implementing a tagging system attached to the questions.
Here are my models:
class question(models.Model):
ques_id = models.AutoField(primary_key=True)
ques_text = models.TextField(max_length=1024, blank=False)
ques_author = models.ForeignKey('author')
ques_created = models.DateField(auto_now_add=True)
ques_dscore = models.IntegerField()
ques_bloom = models.CharField(max_length=3)
ques_subject = models.CharField(max_length=3)
ques_type = models.CharField(max_length=1)
ques_flags = models.CharField(max_length=16)
ques_quiz = models.ManyToManyField('quiz')
def __unicode__(self):
return self.ques_text
class choice(models.Model):
choice_id = models.AutoField(primary_key=True)
choice_text = models.CharField(max_length=256, blank=False)
choice_ques = models.ForeignKey('question')
choice_ans = models.BooleanField(default=False)
choice_tags = models.CharField(max_length=32)
def __unicode__(self):
return self.choice_text
class answer(models.Model):
answer_id = models.AutoField(primary_key=True)
answer_text = models.TextField(max_length=1024)
answer_ques = models.ForeignKey('question')
answer_choice = models.ForeignKey('choice')
answer_tags = models.CharField(max_length=128)
class author(models.Model):
user = models.OneToOneField(User)
domain = models.CharField(max_length=16)
def __unicode__(self):
return self.user.username
# a table for storing all the tags
class tags(models.Model):
tags_id = models.AutoField(primary_key=True)
tags_text = models.CharField(max_length=16)
def __unicode__(self):
return self.tags_text
# table that connects tags with question attached to the tag
# from all the research on the web, it can be infered that
# 3NF tagging (Toxi Solution) is the best way to go
# good for inserts but slow on selects
class tagcon(models.Model):
tagcon_id = models.AutoField(primary_key=True)
tagcon_tags = models.ForeignKey('tags')
tagcon_ques = models.ForeignKey('question')
I have currently applied the 3NF tagging Toxi solution. The issue is that a denormalized system would help in faster selects and a 3NF would be faster inserts but slow searches.
I am confused if I should use ManyToMany field type for tags. Could someone enlighten if it would be better to use a ManyToMany field inbuilt in Django or implement the 3NF system as done?
This is already exactly the same as a ManyToManyField. The only difference is that adding the field would give you an explicit accessor from question to tag.
(Note, your models are very odd. There is absolutely no benefit in prefixing every field name with an abbreviated version of the model name; you can only ever access the field via the model anyway, so you would always be doing question.ques_text, which is redundant. And you shouldn't be defining your own PK fields unless you have a very good reason.)
In my opinion I suggest you try these 2 projects
django-tagging.
django-taggit.

Many-To-Many Fields View on Django Admin

Basically I am trying to recreate a fields in this model that is similar to django user authenticate system, for this I try using many-to-many fields but it ended up like this.
I am trying to have another field that can show what exist and another field for I have chosen similar to django admin, which looks like this.
This is my code
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
class BlogPage(models.Model):
category = models.ManyToManyField(Category)
title = models.CharField(max_length=128)
preview = models.TextField(max_length=256)
content = models.TextField()
I believe what you want is a filter_horizontal widget used in the Admin template. This should help: Django Admin ManyToManyField
currently i am able to display many to many fields is admin panel
models.py
class Abc(models.Model):
course = models.ManyToManyField(Course, blank=True)
admin.py
class AbcsAdmin(admin.ModelAdmin):
"""
Admin panel management for Alumni
"""
list_display = ["id","get_course"]
def get_course(self,obj):
return [course.name for course in obj.course.all()]