Django manytomany restriction

2019-08-08 15:47发布

I am new in database and Django. I have very little knowledge on trigers.

I created a database about an academic expert system and here all the papers should have up to 4 topics. If more topics are selected than ther should be a warning as "too many topics". A topic could be owned by many papers. So it is kind of many-to-4 relation. But I do not know how to limit the upper bound to 4.

My classes are like this:

class Topic(models.Model):
    name = models.CharField(max_length=200)
    title = models.CharField(max_length=200)

class Paper(models.Model):
    expert = models.ForeignKey(Expert)
    topic = models.ManyToManyField('Topic', related_name='topic+', blank=True)
    coauthors = models.ManyToManyField('Expert', related_name='coauthors+', blank=True)
    title = models.CharField(max_length=200)
    citations = models.ManyToManyField('Paper', related_name='citations+', blank=True)

    def __str__(self):
        return self.title

2条回答
beautiful°
2楼-- · 2019-08-08 16:15

I think you should use the clean() method on your model, but not on your form.

First of all because that's something that has to do with your model, not with your form, in the sense that if in the future you have some other form it should make the same control, thus repeating yourself.

You can be sure that the model.clean() method is executed as part of the form validation in the Django docs

Also it is good to follow best practices (unless you know better) and one of MVC-like frameworks best practice is to have fat models

查看更多
叼着烟拽天下
3楼-- · 2019-08-08 16:23

I think you should inspect the data during form submission. Try putting this overloaded clean method into the form and than the form goes into the ModelAdmin definition for your Paper model.

# admin.py
from django.contrib import admin
from django import forms
from django.core.exceptions import ValidationError
from .models import Paper

class PaperForm(forms.ModelForm):
    class Meta:
        model = Paper
    def clean(self):
        topic = self.cleaned_data.get('topic')
        if topic.count() > 4:
            raise ValidationError("To many topics!")
        return self.cleaned_data

class PaperAdmin(admin.ModelAdmin):
    form = PaperForm

admin.register(Paper, PaperAdmin)

Also it is not the best way to define related_name. related_name is supposed to help you refer back to the model from it's relation. Do it like this:

# in your model
topics = models.ManyToManyField('Topic', related_name='papers', blank=True)

# shell
paper = Paper.objects.order_by('?')[0] # get random object
paper.topics.all() # and access it's topics
topic = Topic.objects.order_by('?')[0] # now get random topic
topic.papers.all() # and get it's papers using related_name!

It's better than topic.topic+.all() right? I'm not even sure if it'd work.

查看更多
登录 后发表回答