ManyToManyField with rating using 'through' on each ManyToMany relation in Django

43 views
Skip to first unread message

inoyon artlover KLANGRAUSCH

unread,
Dec 4, 2014, 5:58:31 AM12/4/14
to django...@googlegroups.com

I am very beginner in the programming world, so please forgive my lack of understanding...

There is a CustomUserprofile in my models.py.. nothin very special about this...
class Interests(models.Model):

    RATING = [(y, y) for y in range(1, 7)]

    interest = models.CharField(max_length=40)
    interest_rating = models.SmallIntegerField(choices=WEIGHT)


class CustomUserprofileInterests(models.Model):

    user = models.OneToOneField(User)
    interests = models.ManyToManyField(
            Interests, through='CustomInterests',
            through_fields=('custominterest', 'interest'),
            null=True, blank=True)


class CustomInterests(models.Model):

    WEIGHT = [(y, y) for y in range(1, 7)]

    interest = models.ForeignKey(Interests)
    custominterest = models.ForeignKey(CustomUserprofileInterests)
    rating = models.SmallIntegerField(choices=WEIGHT)
 

I want to accomplish a rating on each relation in the 'interests = ManyToManyField' in my CustomUserprofile. The Interests-Model HAS to have an OWN, self relating rating in each 'interest' entry, NOT related to the CustomUserprofile.

Startet lot of investigation and the 'through' option seems to be the solution? Don't got it really because in my ModelForm and Admin there is NO field to choose some 'interests' and an option to rate it.
Got absolutley NO idea how to do it, would appreciate any hints.

Collin Anderson

unread,
Dec 5, 2014, 9:00:01 AM12/5/14
to django...@googlegroups.com
Hi,

Create an admin Inline like this:

class CustomInterestsInline(admin.TabularInline):
    model
= CustomInterests

class CustomUserprofileInterests(admin.ModelsAdmin):
    inlines
= [CustomInterestsInline]

Collin

inoyon artlover KLANGRAUSCH

unread,
Dec 5, 2014, 9:41:46 AM12/5/14
to django...@googlegroups.com
Did it in this fashion:

models.py

class Interests(models.Model):

ORDER = [(y, y) for y in range(10, 200, 10)] interest = models.CharField( verbose_name='Interesse', max_length=40) interest_order = models.SmallIntegerField(default=None, choices=ORDER) interest_active = models.BooleanField(default=False)

 class Meta:
    verbose_name_plural = 'Interessen'
    ordering = ['interest']

 def __str__(self):
    return self.interest

class Sports(models.Model): ORDER = [(y, y) for y in range(10, 200, 10)] sport = models.CharField(verbose_name='Sportart', max_length=40) sport_order = models.SmallIntegerField(default=None, choices=ORDER) sport_active = models.BooleanField(default=False)

class Meta:
    verbose_name_plural = 'Sportarten'
    ordering = ['sport']

def __str__(self):
    return self.sport

class CustomUserprofileInterests(models.Model): user = models.OneToOneField(User) interests = models.ManyToManyField( Interests, through='CustomInterests', through_fields=('custominterest', 'interest'), verbose_name='Interessen', null=True, blank=True)

sports = models.ManyToManyField( Sports, through='CustomSports', verbose_name='Sportarten', null=True, blank=True)

class Meta: verbose_name_plural = 'Interessensprofil'

def get_full_name(self):
    return self.user

def get_short_name(self):
    return self.user

def __str__(self):
    return '{0} | {1}'.format(self.user, 'Interessensprofil')

class CustomInterests(models.Model):

WEIGHT = [(y, y) for y in range(1, 7)]

interest = models.ForeignKey(Interests)
custominterest = models.ForeignKey(CustomUserprofileInterests)
# interested = models.BooleanField(default=False)
rating = models.SmallIntegerField(choices=WEIGHT)

class CustomSports(models.Model):

WEIGHT = [(y, y) for y in range(0, 7)]

sport = models.ForeignKey(Sports)
custominterest = models.ForeignKey(CustomUserprofileInterests)
# interested = models.BooleanField(default=False)
rating = models.SmallIntegerField(choices=WEIGHT)

AND THE admin.py

class CustomProfile(admin.StackedInline): model = models.CustomUserprofile can_delete = False verbose_name_plural = 'Nutzerprofile'

class CustomUserAdmin(UserAdmin): inlines = (CustomProfile,)

class CustomInterestsInline(admin.TabularInline): model = models.CustomInterests extra = 9

class CustomSportsInlilne(admin.TabularInline): model = models.CustomSports extra = 9

admin.site.register(models.Interests) admin.site.register(models.Sports) admin.site.register(models.CustomUserprofileInterests) admin.site.register(models.CustomInterests) admin.site.register(models.CustomSports) admin.site.register(models.CustomUserprofileInterests, CustomUserprofileAdmin)


The nexts steps I want to accomplish:

A form for users, they can create/edit the profile. The 'interests' and 'sports' columns have to be prepopulated with all available (declared by 'active' with a Boolean) entries in the interests/sports table. If a user has an 'interest' or 'sports', he/she selects it (checkbox) and rates the entry.

Also the amount of entries to be selected by the user is limited to a defined amount (i.e. 6 or 10) (here would be form validation best practice?)

Collin Anderson

unread,
Dec 6, 2014, 12:54:44 PM12/6/14
to django...@googlegroups.com
Hi,

To limit the number or rows in an inline, max_num is usually the way to go.
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.max_num

As far as having the list of all possibilities available as options goes, it gets a little more complicated and I don't think it's something the admin really handles out of the box. You're starting to get to a complicated enough case where it might make sense to roll your view and form code.

It might be possible to do it with a custom form and the proper "initial" argument to your formset.

Collin
Reply all
Reply to author
Forward
0 new messages