I have 2 models: a wishlist model and a wish model. A wishlist is made of n wish (wish have a reference to his wishlist). I would like update a wishlist with a form. Here is the form I'd like to have:
input:text wishlist.name
for wish in wishlist:
input:text wish.name
input:number wish.price
I'm new to django and don't know how to build a form that handle two models.
# models.py
class WishList(models.Model):
name = models.CharField(max_length=200)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_date = models.DateTimeField('date of creation')
class Wish(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=24, decimal_places=2)
description = models.TextField(max_length=200)
wishlist = models.ForeignKey(WishList, on_delete=models.CASCADE)
Related
I have an issue with displaying list of related articles in my Q&A DetailView.
I have a field where user can connect an article to Q&A from admin site. What I want is to display these related articles.
models.py
class QA(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
title = models.CharField(max_length=750)
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
related_articles = models.ManyToManyField(Article, default=None, blank=True, related_name='related_article')
slug = models.SlugField(unique=True, blank=True)
class Article(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
title = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
slug = models.SlugField(unique=True, blank=True)
views.py
class QADetailView(LoginRequiredMixin, DetailView):
login_url = 'login'
redirect_field_name = 'login'
template_name = 'QADetailView.html'
model = QA
def get_context_data(self, **kwargs):
categories = Category.objects.all()
related_articles = Article.objects.filter(related_article=self.kwargs['id']) #No idea what to put in filter
#related_articles = Article.objects.filter(related_article='1')
context['related_article'] = related_articles
context['categories'] = categories
return context
QADetailView.html
{% for article in related_article %}
{{article.title}}
{% endfor %}
You don' t need to inject the related articles in the template context, you can simply write in your QADetailView.html template (without any necessary edit):
{% for article in object.related_articles.all %}
{{article.title}}
{% endfor %}
Check RedWheelBorrow's solution first. If that does not work. Try the following:
There might be a better way of structuring your classes. So in Django, it is possible to simulate a hierarchy. For instance, when creating an invoice representation it would look something like this.
from django.db import models
class Invoice(models.Model):
"""Representing a invoice"""
user = models.ForeignKey(to=User, on_delete=models.PROTECT, related_name="invoices", default=1)
title = models.CharField(max_length=200)
date = models.DateField()
start_time = models.TimeField(default=time(9))
duration = models.IntegerField(default=1)
invoice_number = models.CharField(max_length=500, default=increment_invoice_number) # increment_invoice_number this a function that I will leave out of this answer
class InvoiceLine(models.Model):
"""Representing invoice lines of an invoice"""
invoice = models.ForeignKey(to=Invoice, on_delete=models.CASCADE, related_name="lines")
description = models.CharField(_("Beschrijving"), max_length=512)
quantity = models.IntegerField(_("Aantal"), blank=True, default=1)
discount = models.IntegerField(_("Korting in %"), default=0)
Please note, the invoice representation as presented here lacks some attributes to be a fully functional class in production. It still needs tax references, etc. However, it holds the solution to your problem.
The Invoice class has an attribute user that holds a ForeignKey with 'invoices' being its related name. This means it the object must be linked to a User object.
A User can have multiple Invoices. An Invoice can only be linked to one User.
It is one-to-many relationship:
User -> List[Invoice,...]
When looking at the class InvoiceLine we see a similar pattern. The attribute invoice is a ForeignKey with a link to the Invoice class and holds 'lines' as related name. This is also an one-to-many relationship.
Invoice -> List[InvoiceLine, ...]
To obtain the linked objects we can use the following code:
# obtain user
user = User.objects.get(id=<USER_ID>)
# obtain all Invoice objects linked to user
invoices = user.invoices.all()
# print all string representations of Invoice objects
print(invoices)
# obtain all InvoiceLine objects linked to invoices
for invoice in invoices:
lines = invoice.lines.all()
print(lines)
In the above example the highest object is User. A User can hold multiple Invoice objects. A Invoice object can hold multiple InvoiceLine objects. We can use the same strategy to solve your problem.
We want the following representation:
User -> List[QA, ...]
QA -> List[Article, ...]
class QA(models.Model):
id = models.AutoField(primary_key=True)
# So in your case the author is the user.
# Here you define User -> List[QA, ...]
author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
title = models.CharField(max_length=750)
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
slug = models.SlugField(unique=True, blank=True)
# related_articles is removed.
class Article(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
title = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
slug = models.SlugField(unique=True, blank=True)**
related_articles = models.ForeignKey(to=QA, on_delete=models.CASCADE, related_name="related_articles")
class QADetailView(LoginRequiredMixin, DetailView):
login_url = 'login'
redirect_field_name = 'login'
template_name = 'QADetailView.html'
model = QA
def get_context_data(self, **kwargs):
categories = Category.objects.all()
# obtain specific QA
qa = QA.objects.get(pk=id, author=self.request.user)) # check how you named the id variable in your url.
# obtain related articles
related_articles = qa.related_articles.all()
# Save in context for use in template.
context['related_articles'] = related_articles # Added an character 's' to key value for there is can be more than one related article.
context['categories'] = categories
return context
{% for article in related_articles %} # Also add character 's' here
{{article.title}}
{% endfor %}
This should do the trick. There might be some improvements on error handling though
I hope this works. If not, let me know.
So I have a social media app, where users can like the posts of other users. Now I want to fetch the top 20 users who have received the most number of likes. I am pretty much confused how to query my Likes Model
My LIKES MODEL
class PostLike(models.Model):
user_who_liked = models.ForeignKey(User, on_delete=models.CASCADE)
post_liked = models.ForeignKey(Post, on_delete=models.CASCADE)
liked_on = models.DateTimeField(default=timezone.now)
SIMPLIFIED POST MODEL
class Post(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
caption = models.TextField()
date = models.DateTimeField(default=timezone.now)
likes = models.ManyToManyField(
User, blank=True, through=PostLike)
image = models.TextField()
class Meta:
ordering = ['-id']
SIMPLIFIED USER MODEL
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
user_name = models.CharField(max_length=100, unique=True)
date = models.DateTimeField(default=timezone.now)
profile_picture = models.TextField(
default="https://www.kindpng.com/picc/m/24-248253_user-profile-default-image-png-clipart-png-download.png")
bio = models.CharField(max_length=200, default="")
objects = CustomManger()
def __str__(self):
return self.user_name
** My View **
#api_view(["GET"])
#permission_classes([IsAuthenticated])
def leaderboard(request):
# I dont know how to query the PostLike model now to get the most liked users
pass
First I changed the user attribute in your Post model, I added related_name because otherwise the related names were clashing. This is the definition I used, otherwise your models are unchanged.
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
I.e. the posts by a user are accessible on User via the author attribute.
The following query gives you the top 20 users by number of likes they received:
User.objects.annotate(num_likes=Count('author__likes')).order_by('-num_likes')[:20]
Explanation:
Query User model and
annotate each user by doing a count:
author leads to the posts by the user
likes follows to PostLike and counts all likes which are associated with a post by the user
then order by number of likes descending,
and limit the number of retrieved objects to 20.
I am currently trying to organize a django database model for an online shop-system with users and products.
My code:
class UserData(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=500)
bought_products = models.ForeignKey(MarketProducts, on_delete=models.CASCADE)
class VendorData(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=500)
sold_products = models.ForeignKey(MarketProducts, on_delete=models.CASCADE)
class MarketProducts(models.Model):
category = models.CharField(max_length=100)
vendor = models.ForeignKey(VendorData, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
price = models.IntegerField()
pub_date = models.DateTimeField('Date published')
image = models.ImageField(upload_to=b'shop/media/images/')
likes = models.IntegerField()
dislikes = models.IntegerField()
How can I organize a good working system so all the products a user bought are saved inside the bought_products column and all the products a vendor sold can be saved inside the sold_products column. Do I have to use a ForeignKey for that or is there something more suitable for this situation? Also, if there is anything unwise about the existing structure of the database model (for example the current image field column only saves the link but not the image itself which is kinda weird...), please feel free to correct me :).
Many thanks in advance :D
In this case I suggest to make bought_products and sold_products instances of ManyToManyField because the same product can be bought by multiple Users and sold by multiple vendors
Firstly I would start by reading the following documentation on django auth customization. Seems like that would help you out a little bit.
https://docs.djangoproject.com/en/2.2/topics/auth/customizing/
Additionally, I think you need to better evaluate your data modelling to make each model more explicit/clearly defined. See example below:
class Products(models.Model):
vendor = models.ForeignKey(VendorData, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
price = models.IntegerField()
pub_date = models.DateTimeField('Date published')
image = models.ImageField(upload_to=b'shop/media/images/')
likes = models.IntegerField()
dislikes = models.IntegerField()
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100)
active = models.BooleanField(default=True)
class ProductCategory(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_add_now=True)
From there I would construct a separate model which would store the customer purchased items. Since you already have a model which stores the vendor to product data, you shouldn't need anything additional to identify how many sales a particular vendor has.
I have models of Exercise, Training and Workout.
Training contains some exercises (Exercise)
Workout contains trainings (Training).
Snippet of my models.py:
class Exercise(models.Model):
user = models.ForeignKey(User, related_name='exercises',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.TextField(max_length=300)
details = models.ManyToManyField(ExerciseDetail, blank=True)
...
class Training(models.Model):
user = models.ForeignKey(User, related_name='trainings',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.CharField(max_length=250)
exercises = models.ManyToManyField(Exercise, related_name='trainings',
blank=True)
...
class Workout(models.Model):
user = models.ForeignKey(User, related_name='workouts',
on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=200)
description = models.TextField(max_length=400, blank=True)
trainings = models.ManyToManyField(Training, related_name='workouts',
blank=True)
...
I would like to have possibility to use something like Workout.objects.get(name='workout').exercises.objects.all() to get a list/set of all exercises included in trainings of chosen Workout.
I would also like to have possibility to use exercises`` field with Django Rest Framework to list all exercises, possibly with link to particularExercise``` model serializer.
Can someone give a hint how can I do that?
You can query this with:
Exercise.objects.filter(
trainings__workouts__name='workout'
)
With the consecutive underscores (__), you thus can look "through" relations.
This will thus return the Exercises that belong to Trainings that belong to Workouts with as name 'Workout'.
How to implement a list in a Django model?
Lets say I have a UserProfile model, and each user can have a list of mortgages (undefined quantity) defined by MortgageModel.
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# list of morgtages?
my only idea is to make a old school list, where every mortgage can point to another one or null, like this:
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
next_mortgage = MortgageModel(null=True, default=null)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
mortgages = MortgageModel(null=True, default=null)
is there any other possibility?
You'll have to assign a ForeignKey to User , so that each Mortgate 'belongs' to a user.
That is how a One-To-Many relationship is done. Then, if you want to get the list of Mortgages a user have, you'd filter them out like MortgageModel.objects.filter(related_user=user)
So, you'd have something like
Model
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
related_user = models.ForeignKey(UserProfile)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
View
list_of_mortages = MortgageModel.objects.filter(related_user=user)