简体   繁体   中英

How to relate many-to-many relationship on same page in django-admin?

I am new to django and i am trying to create a simple blog application.

In my models.py i have defined 3 models for post, Commetns and tags.

models.py

from django.db import models
from django.contrib.auth.models import User


# Create your models here.


class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField('post body')
    author = models.ForeignKey(User)
    pub_date = models.DateTimeField('date published')
    is_published = models.BooleanField(default=0)
    featured_image = models.CharField(max_length=200)
    created_date = models.DateTimeField('date created')
    updated_date = models.DateTimeField('date Updated')

    def __str__(self):
        return self.title


class Comment(models.Model):
    post = models.ForeignKey(Post)
    user = models.ForeignKey(User)
    comment_text = models.CharField(max_length=200)
    created_date = models.DateTimeField('date created')
    is_published = models.BooleanField(default=0)

    def __str__(self):
        return self.comment_text


class Tags(models.Model):
    title = models.CharField(max_length=200)
    post = models.ManyToManyField(Post)

    def __str__(self):
        return self.title

as you can see that tags and posts have many-to-many relation with each other.

Now In my admin panel for the blogs module I want the user to be able to add posts, comments and tags on the same page ie ( when creating or updating a post ).

I can successfully do this for posts and comments, however i don't have the idea of how to attach tags so that i can add new tags and attach them to the posts at the same time. Also i would like to use select2 plugin for the tags field.

my admin.py

from django.core import serializers
from django import forms
from django.http import HttpResponse
from django.utils import timezone
from django.contrib import admin
from .models import Post, Comment, Tags


# Register your models here.


class CommentsInline(admin.StackedInline):
    model = Comment
    extra = 1
    fields = ['comment_text']



class TagsInline(forms.ModelForm):
    # I am not sure what should i put in this class 
    model = Tags
    fields = ('title', )
    filter_vertical = ('post', )


class PostAdmin(admin.ModelAdmin):
    fieldsets = [
        ('Content', {'fields': ('title', 'body', 'is_published')}),
        ('Date Information', {'fields': ('pub_date', )})
    ]

    inlines = [CommentsInline, TagsInline]



admin.site.register(Post, PostAdmin)

When trying to run the above code i always see this error :

'blog.Tags' has bno foriegn key to 'blog.Post'

What you're looking for is nested inline admin. Django doesn't have this out of the box, but there is a package for it - https://github.com/s-block/django-nested-inline . I used it with a django 1.5 project a couple of years ago and it did what you seem to be looking for.

In response to your comment, the error message is correct. There is no direct foreign key between Tag and Post . Django uses an intermediate table for ManyToManyField . Check out the admin documentation for many-to-many models and see if that helps you out.

Give a related name to post field in Tags Model. Though Django generates a default related name for reverse relationship. I guess it will be "post_set".

post = models.ManyToManyField(Post, related_name="tags")

Then in admin model for Post use

filter_horizontal = ('tags',)

You will see a nice widget to add tags to post in admin panel. Also a + button on it's side to add new tags on the fly.

No use of TagsInline class.

PS: IMO your Post model should contains tags field with ManytoMany relationship because in reality post have tags not the other way around. Though Django doesn't differentiate between these two cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM