Need help with unique_together - on ForeignKey and Boolean field

991 views
Skip to first unread message

ThomasTheDjangoFan

unread,
Nov 17, 2014, 2:51:16 AM11/17/14
to django...@googlegroups.com
Hi guys,

I'd like to only be able to assign many ProcutImages to a Product, but only ONE Image as a default image per product (ProductImage.is_default_image=True).

I can't get this to work correnctly on Django 1.7 with a db.sqlite3: With the code below I can only assign ONE Image to a Product. After that I get the error "Product image with this Product und Is default image already exists.".

Am I getting something wrong?

from django.db import models

class Product(models.Model):
    title
= models.CharField(max_length=255)
   
    is_active
= models.BooleanField(default=True)


class ProductImage(models.Model):
    product
= models.ForeignKey(Product)

    image
= models.ImageField(upload_to='products/images/')

    is_default_image
= models.BooleanField(default=False,null=False,blank=False)

   
class Meta:
       
# A product can have multiple ProductImages, but only one of them can be the "default"-image
        unique_together
= ('product', 'is_default_image')

I would be really thankful for some tips.

Kind regards
Thomas

Jani Tiainen

unread,
Nov 17, 2014, 5:25:37 AM11/17/14
to django...@googlegroups.com
Well boolean field can have only two values: "true" or "false".

Now your unique_together defines that for "product" combined with "is_default_image" must be unique. Which means that for each product you can have _two_ images, one where is_default_image is true and one where is_default_image is false. And this is forced on database level as well.

But apparently that is what you intended to do. There isn't really one single solution for your problem.

--

Jani Tiainen

ThomasTheDjangoFan

unread,
Nov 17, 2014, 6:10:08 AM11/17/14
to django...@googlegroups.com
Hi Jani,

thanks for making it clear. smile.png


Actually I would like to assign a lot of images to a product and only have one image as the default image.

How would you do this? Can you give me a hint?

Javier Guerra Giraldez

unread,
Nov 17, 2014, 9:12:50 AM11/17/14
to django...@googlegroups.com
On Mon, Nov 17, 2014 at 6:10 AM, ThomasTheDjangoFan
<stefan.eich...@googlemail.com> wrote:
>
> How would you do this? Can you give me a hint?


4 different ways:

- don't do it as a flag, add a 'defaultImage=ForeignKey(ProductImage)'
to the Product class.

- don't use False for non-default, use NULL. since two NULL values
aren't equal, they don't trip unique restriction

- don't use True/False, use an integer to give images some priority.
#1 is default, the others get 2...n

- use a partial index (supported by PosgreSQL and SQLite), it's not
directly supported by the ORM, but you can simply add as an "ALTER
TABLE CREATE UNIQUE INDEX ProductdefaultImage ON app_productimage
(image) WHERE is_default_image;" at creation and forget about it.


--
Javier

ThomasTheDjangoFan

unread,
Nov 18, 2014, 12:46:51 AM11/18/14
to django...@googlegroups.com
Hi Javier,

oh yes! You seem to be a really creative and experienced programmer!  smile.png

My solution will be way number 5:
5) Do not set unique_together - forget about it and give the model a function "get_default_image", which returns the first "default_image=True" in the list.

Thanks a lot for your help! This was really inpiring! smile.png

Have a good one

Chuka Nwadiogbu

unread,
Oct 5, 2018, 12:36:48 PM10/5/18
to Django users
Hi, I know it has been a while since this question was asked but I have  a similar question. I have a Post model, and I want there to be one pinned post out of the list of all posts, I tried creating a new property thus, 
   
```pinned = models.BooleanField(default=False, unique=True)```

but it caused major problems. I want to have just one pinned post and the rest unpinned but that would mean pinned = True for one post/article and pinned=False for the rest and I don't think that is how unique is supposed to work. Unique is supposed to be different for all the objects right? not sure how to tackle this problem.

someone suggested I use a foreignkey field to link them all together but now if I'm being honest, I actually do not know where to go from here 

```class PinnedPost(models.Model):
pinned_post = models.ForeignKey(Post, related_name='pinned', on_delete=models.CASCADE)``` if there's anyone here that can help me with this please, I'd really appreciate it. 

heriberto ochoa

unread,
Oct 5, 2018, 12:46:45 PM10/5/18
to django...@googlegroups.com
well, maybe using forms, and the parameter initial of the send form to the template
https://docs.djangoproject.com/en/2.1/ref/forms/fields/#initial
or directly with javascript

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/31bc4205-e1fd-4e59-aa47-a488884253eb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Manjunath

unread,
Oct 5, 2018, 1:02:00 PM10/5/18
to Django users
How are you deciding which post is pinned?
The unique approach might not do any good to you.
A simple solution is to update the pinned values of each post to False & setting the required post pinned value to True when you are setting a pinned post.
There may be better solutions, but I hope this might help you.
Reply all
Reply to author
Forward
0 new messages