Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django manytomany restriction

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
like image 844
Burak Avatar asked Nov 26 '25 12:11

Burak


1 Answers

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.

like image 173
gwaramadze Avatar answered Dec 05 '25 01:12

gwaramadze



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!