0

I want to implement a wishlist for the products in my Django site so that I can represent them in a wishlist page to the user.

the products are in the products app.

products.models.py

class ControlValves(models.Model):
    title = models.CharField(max_length=50, unique=True)    
    product_name = models.CharField(max_length=50, blank=True)
    ....

class Accessories(models.Model):
    title = models.CharField(max_length=50, unique=True)    
    description = models.CharField(max_length=50, blank=True)
    ....

There is a services app that contains various services(models). Then I want to create a wishlist in users app.

users.models.py

class Wishlist(models.Model):
    owner = models.ForeignKey( User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50, null=True, blank=True)
    item = models.ForeignKey( which_model_should_be_here??? , on_delete=models.CASCADE)

since I am fetching the list of products and services from two different apps and within each, there are various models:

question:
1- I don't know how to point to the selected product or service? should I declare a foreign key to each possible product model o services model, or there is another efficient way?

2- an example of how to load them to show to the user( i.e. how to write a query to load them from DB) would be great.

I also checked the answer to this and this, but they are fetching products from just one model, so it's easy because there should be just one foreign key.

Shahriar.M
  • 818
  • 1
  • 11
  • 24
  • Look at this when you can have multiple models for one foreign key: https://stackoverflow.com/questions/881792/how-to-use-dynamic-foreignkey-in-django – Guillaume Dec 22 '20 at 10:29

2 Answers2

1

I think a simple ManyToMany relation should work here. For example:

class Wishlist(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50, null=True, blank=True)
    accessories = models.ManyToManyField(Accessories)
    services = models.ManyToManyField(ControlValves)

And to show them in template, you can simply use:

{% if user.is_authenticated %}

    {% for wish in user.wishlist_set.all %}
         {{ wish.title }}
         {% for accessory in wish.accessories.all %}
            {{ accessory.title }}
         {% endfor %}
         {% for service in wish.services.all %}
            {{ service.title }}
         {% endfor %}
    {% endfor %}

{% endif %}

Update based on comments

If you have 10 model classes which can be added to the WishList model, then above approach won't work. Consider using the following:

class Wishlist(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50, null=True, blank=True)

class WishListItem(models.Model):
    wishlist = models.ForeignKey(WishList, on_delete=models.DO_NOTHING, related_name='wishitems')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

Reson for this is that it is not practical to have 10 m2m relation. Instead using GenericForeginKey to add any of the models you want to add to the WishListItem instance.

Now if you want to display them in template, then use the following code:

{% if user.is_authenticated %}

    {% for wish in user.wishlist_set.all %}
         {{ wish.title }}
         {% for wishitem in wish.wishitems.all %}
            {{ wishitem.content_object }}
         {% endfor %}
    {% endfor %}

{% endif %}

FYI, reason for M2M or adding extra model for items is that user can have multiple wishlists, so it is better to hold them in on DB table, and items in different.

ruddra
  • 50,746
  • 7
  • 78
  • 101
  • So, do you mean there should be a `services = models.ManyToManyField(ControlValves)` for each of the models? e.g. I have like 10 seperate models, then there should be 10 different manytomany keys? – Shahriar.M Dec 22 '20 at 11:55
  • Each item is from a category(model), why should I use ManyToMany key? Why not Fieignkey? – Shahriar.M Dec 22 '20 at 12:41
  • I want to have only one wishlist, so I merged classes to one and kept only `owner` `content_type` `object_id` and `content_object` fields. `owner` and `object_id` are clear, but what to put for `content_type` when I want to create a field in `views.py`? here: `wishlist = Wishlist( owner=owner, object_id=object_id, content_type=???????, content_object=?????) wishlist.save()` – Shahriar.M Dec 22 '20 at 15:31
  • Just add content_object to the object you want to store – ruddra Dec 22 '20 at 15:41
  • I return the item from template to `views.py` within a form and this is the error: `TypeError Wishlist() got an unexpected keyword argument 'content_object'` – Shahriar.M Dec 22 '20 at 16:02
  • You have to check your implementation because you might have named the field differently – ruddra Dec 22 '20 at 17:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226305/discussion-between-shahriar-m-and-ruddra). – Shahriar.M Dec 22 '20 at 17:18
  • Thank you, since I wanted only one wish list, I made a class with `GenericForeignKey` for wished items. And added a `GenericRelation` field pointing to that wishlist class in every product's model. it worked just fine. – Shahriar.M Dec 24 '20 at 11:50
0

This is just but my suggestion:

create a list of types which represent product model

types=((0, "ControlValves"),(1, "Accessories"))

class Wishlist(models.Model):
    owner = models.ForeignKey( User, on_delete=models.CASCADE)
    item_id = models.IntegerField()
    item_type = models.IntegerField(choices=types)

Then on your views.py

 def get_wishlist(request):
     allList = models.Wishlist.objects.filter(ownder=ownder_id)
     items = []
     for listItem in allList:
        if listItem.item_type==0:
           product = models.ControlValves.objects.get(pk=listItem.item_id)
           item = {"id": listItem.id, "title": product.title, ...}
           items.append(item)
        elif listItem.item_type==0:
           product = models.Accessories.objects.get(pk=listItem.item_id)
           item = {"id": listItem.id, "title": product.title, ...}
           items.append(item)
      return HttpResponse(items)
Richard Ochom
  • 485
  • 4
  • 16