1

I'm new to Django so I make 3 simple tables to return a WishList. The thing is that I want whenever user asks for WishList, his/her user_id is used to make a SELECT query to return his/her own WishList. And I want to get product title and product url from my WishList table. I'm using to_field but with that way I only can get product title back. I don't know much about Django so help me!

Product

class Product(models.Model):
    class Meta:
        unique_together = (('id', 'title'),)
    title = models.CharField(max_length=200, unique=True,
                             help_text='Name of the product')
    url = models.CharField(max_length=300, default='',
                           help_text='Url of the product')

    def __str__(self):
        return 'Product: {}'.format(self.title)

WishList

class WishList(models.Model):
    class Meta:
        unique_together = (('user', 'product'),)

    user = models.ForeignKey(fbuser,
                         on_delete=models.CASCADE,
                         help_text='Facebook user',
                         to_field='user_id')
    product = models.ForeignKey(Product, to_field='title', db_column='title',
                            on_delete=models.CASCADE)

    def __str__(self):
        return 'WishList: {}'.format(self.user)
Khoa Nguyen
  • 91
  • 1
  • 3
  • 15

1 Answers1

1

It's not a good practice to override to_field to another field different than your model.pk unless you have a really good reason and you know what you are doing (definitely not the case right now).

So after you read the docs, you will know that in order to get wishlisht related to a user, you can use the ForeignKey reverse relation to get all related wishlists for a user.

user_wishlists = my_user.wishlist_set.all()
#Because we know that you want to access the wishlist.products
#in order to optimize things (in terms of db queries)
#you can add and .select_related('product')
#e.g, user_wishlists = my_user.wishlist_set.all().select_related('product')

#now follow the wishlist.product foreign key to access the related product for every wishlist
for wishlist in user_wishlists:
    product = wishlist.product
    print (product.id, product.title, product.url)

Now after you read a little bit more of the documentation you will notice that your WishList model is in fact an intermediate model for a ManyToMany relation between User and his wished products, then you will know that you can define a M2M field between user and products via WishList like so:

class FbUser(models.Model):
    #...
    wished_products = models.ManyToManyField(
        Product,
        through='WishList',
        through_fields=('user', 'product')
    )

#and now accessing user wished products would be easy as:
user_wished_products = my_user.wished_products.all()
for product in user_wished_products:
    print (product.id, product.title, product.url)
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Todor
  • 15,307
  • 5
  • 55
  • 62
  • `AttributeError: 'unicode' object has no attribute '_meta'` I got this error, it causes because first parameter to `ManyToManyField` must be either a model, a model name or string. It's weird because `Product` is a model – Khoa Nguyen Oct 19 '16 at 12:50
  • I guess the `Product` class is defined in another application? Try to refer it with the application name too, e.g. `'myapp.Product'`. – Todor Oct 19 '16 at 13:52
  • Yes, all 3 tables are all made in different application. I tried to use `'myapp.Product'` but it doesn't work for me. What I did is just add a column `url` in my WishList model, then return it with the title also. It worked but I dont think that it's good code. So i'm still trying to better my code – Khoa Nguyen Oct 20 '16 at 08:33
  • Instead of writing it as a string `'myapp.Product'`, try to import the class (e.g. `from myapp.models import Product`), then send that to the M2M field definition: `models.ManyToManyField(Product, ....)` (no string used). – Todor Oct 20 '16 at 09:02