ManyToManyField ломается на экранах администратора и не должно быть - PullRequest
0 голосов
/ 10 марта 2020

У меня есть некоторые модели, подобные этой:

class Category(models.Model):
    class Meta:
        ordering = ['name']

    name = models.CharField(max_length=100)
    text = models.TextField(blank=True)

    def __str__(self):
        return self.name

class Tag(models.Model):
    name = models.CharField(max_length=100)
    def __str__(self):
        return self.name

class Tool(models.Model):
    name = models.CharField(max_length=30, null=True, default='')   
    url = models.URLField(max_length=250, null=True, default='')
    image_url = models.URLField(max_length=250, null=True, default='', blank=True)
    about = models.TextField(default='', null=True, blank=True)
    tags = models.ManyToManyField( Tag, related_name="tools" , blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True, related_name="category1")
    altcategory = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True, related_name="category2")

И все кажется нормальным, кроме случаев, когда я go добавляю тег для инструмента на экранах администратора. Я могу создать инструмент и тег, но когда я выбираю тег в списке тегов на экранах администратора и сохраняю, я получаю:

The above exception (syntax error at or near "ON" LINE 1: ...ls_tool_tags" ("tool_id", "tag_id") VALUES (1, 2) ON CONFLIC... ^ ) was the direct cause of the following exception:

с sql:


('INSERT INTO "tools_tool_tags" ("tool_id", "tag_id") VALUES (%s, %s) ON '
 'CONFLICT DO NOTHING')

Экран DEBUG говорит, что ошибка в "tag_id", странно ...

Я надеюсь, что это не версия, так как я использую Heroku и был действительно впечатлен тем, как все "просто работает". Моя Django версия '3.0.4' и Postgres 12.2.

1 Ответ

0 голосов
/ 11 марта 2020

Я не думаю, что ManyToMany работает из коробки. Поэтому мне пришлось создать сквозную модель ... и изменить форму администратора на эту ...

models.py

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.auth.models import User
from django.utils.html import format_html
from django.contrib.contenttypes.models import ContentType

class Category(models.Model):
    class Meta:
        ordering = ['name']

    name = models.CharField(max_length=100)
    text = models.TextField(blank=True)

    def __str__(self):
        return self.name



class Tag(models.Model):
    name = models.CharField(max_length=100)
    def __str__(self):
        return self.name

class Tool(models.Model):
    name = models.CharField(max_length=30, null=True, default='')   
    url = models.URLField(max_length=250, null=True, default='')
    image_url = models.URLField(max_length=250, null=True, default='', blank=True)
    about = models.TextField(default='', null=True, blank=True)
    tags = models.ManyToManyField( 
        Tag, 
        through="PageTags",
        through_fields=('tool', 'tag'))

    category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True, related_name="category1")
    altcategory = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True, related_name="category2")

    def _get_thumbnail(self):
        return format_html(u'<img src="{}" width="150"/>', self.image_url)
    _get_thumbnail.allow_tags = True

    def _get_link(self):
        return format_html(u'<a href="{}" target="_blank"/>{}</a>', self.url, self.url)
    _get_link.allow_tags = True

    def __str__(self):
        return self.name + ": " + self.url

class PageTags(models.Model):

    tag = models.ForeignKey(Tag ,   on_delete=models.CASCADE, )
    tool= models.ForeignKey(Tool ,  on_delete=models.CASCADE, )
    amount = models.IntegerField(default=0)

... и admin.py на эту ...

from django.contrib import admin
from django.contrib.admin import TabularInline 
#from django.contrib.contenttypes.admin import  GenericTabularInline

from django.utils.html import format_html_join
from django.utils.safestring import mark_safe

from .models import Tool, Category, Tag, PageTags


class PageTagsInline(admin.TabularInline): 
    model = PageTags
    extra = 1


class ToolAdmin(admin.ModelAdmin):
    #fields = ('name', )

    list_display = ('name','_get_link','category','altcategory', "_get_thumbnail", )
    list_filter = ('category',)
    search_fields = ['name', "about"]
    filter_horizontal = ('tags',)
    inlines = [PageTagsInline,]


admin.site.register(Tag)
admin.site.register(Category)
admin.site.register(Tool, ToolAdmin)

И интерфейс другой, не похожий на виджеты разрешений, но ОК ... по крайней мере, не бомбить админа.

...