I have 3 models :
class Product(models.Model):
name = models.TextField()
class Company(models.Model):
name = models.TextField()
users = models.ManyToManyField('auth.User')
class Sales(models.Model):
product= models.ForeignKey(Product)
company= models.ForeignKey(Company)
seller = models.ForeignKey('auth.User')
My goal is to display the list of all products sold by the company of request.user so in my views I do :
Enterprise= Company.objects.filter(users=request.user)[0]
Products_sold = Sales.objects.filter(company=Enterprise)
But since I have a lot of views I'm wondering if there is a way to it directly in the model?
Your user should have company_set:
Products_sold = Sales.objects.filter(request.user.company_set.all()[0])
Related
My models
User
class User(AbstractUser):
is_student = models.BooleanField(default=False)
....
purchased = models.ManyToManyField(Course, blank=True)
Course
class Course(models.Model):
title = models.CharField(max_length=1000)
.....
price = models.FloatField()
My Views
class StudentPurchasedcourse(ListView):
model = Course
template_name = 'tutspack/purchasedcourse.html'
context_object_name = 'course'
def get_queryset(self):
queruset = Course.objects.filter(pk=self.request.user.purchased.all()).order_by('title')
return queruset
My Urls.py
path('purchased_course/', views.StudentPurchasedcourse.as_view(), name='purchased-course'),
I want to return all the courses That student have purchased on the studentViewpage.
You should use reverse relation for such query. Start with adding related_name to purchased field of User:
class User(AbstractUser):
...
purchased = models.ManyToManyField(Course, blank=True, related_name="buyers")
Then you can easily use that name in making queries based on relations:
Course.objects.filter(buyers=self.request.user).order_by('title')
More about queries
So I have a product Model which say looks like this :
class ProductModel(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
and I also have a cart model which looks like this :
class CartModel(models.Model):
customer = models.ForeignKey(User, on_delete= models.CASCADE, related_name="cart")
products = models.ManyToManyField(ProductModel)
the thing is I want to add a quantity field to the product so the user can add multiple products from the same product in the cart But I only want it when the product is in a cart (I don't want to add it in the ProductModel) Instead I want to add it to the product fields in the many to many relationship. I've done a bit of research and most of the answers aren't clear enough on how I should be doing this.
You can create new fields in the intermediate relation table between Products and Cart. You have to define a new class for this intermediate table and to use it with the through attribute of the M2M field.
from django.db import models
from django.contrib.auth.models import User
class ProductModel(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Product"
class CartModel(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="cart")
products = models.ManyToManyField(ProductModel, through='ProductCart')
def __str__(self):
return "Cart nÂș {} - {}".format(self.pk, self.customer)
class Meta:
verbose_name = "Cart"
class ProductCart(models.Model):
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE)
cart = models.ForeignKey(CartModel, on_delete=models.CASCADE)
quantity = models.IntegerField()
def __str__(self):
return ' '
One way for displaying it in the admin can be to use TabularInline for the products of the cart:
from django.contrib import admin
from .models import CartModel
class ProductsInline(admin.TabularInline):
model = CartModel.products.through
extra = 0
exclude = ()
verbose_name = 'Product'
class CartAdmin(admin.ModelAdmin):
list_display = ('customer',)
list_filter = ('customer',)
inlines = [
ProductsInline,
]
admin.site.register(CartModel, CartAdmin)
I know how I can count things with annotate (in my view) but I would like to do the same in model (so it would be more reusable).
For example (lets take an example from django documentation) I have this model:
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class Publisher(models.Model):
name = models.CharField(max_length=300)
class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
pubdate = models.DateField()
class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
and I can use in view this:
from django.db.models import Count
pubs = Publisher.objects.annotate(num_books=Count('book'))
But how I do that in model?
I know this question is pretty basic (probably) but I'm pretty much beginner in django.
Thanks for answers!
You can use custom managers:
Django docs: Managers
class BookManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(num_books=Count('book'))
class Publisher(models.Model):
name = models.CharField(max_length=300)
books = BookManager()
Now you can call it like this:
pubs = Publisher.books.all()
And you will have num_books with your objects.
You can use classmethod for this.
class Publisher(models.Model):
...
#classmethod
def get_book_count(cls):
return cls.objects.annotate(num_books=Count('book'))
You can call this method as
pubs = Publisher.get_book_count()
Edit - Also check out the answer by #Navid2zp which might be a better solution for you.
I'm new in Django and DRF, have questions with serialization.
I have models:
class Commodity(models.Model):
shop = models.ForeignKey(Company, on_delete=models.PROTECT)
price = models.DecimalField(max_digits=10, decimal_places=2)
active = models.BooleanField(default=False)
class Clother(models.Model):
commodity = models.ForeignKey(Commodity, related_name='commodity', on_delete=models.CASCADE)
color = models.ManyToManyField(Color, related_name='color')
material = models.ManyToManyField(Material, related_name='material')
gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=UNISEX)
class Outwear(models.Model):
clother = models.ForeignKey(Clother, on_delete=models.CASCADE)
name = models.CharField(max_length=30, blank=True)
outwear_type = models.ForeignKey(OutwearType, on_delete=models.CASCADE)
size = models.ManyToManyField(ClotherSize)
So I suppose to make a Serializer like that:
class OutwearSerializer(serializers.ModelSerializer):
commodity = CommoditySerializer(many=False, read_only=False)
clother = ClotherSerializer(many=False, read_only=False)
class Meta:
model = Outwear
fields = ('commodity', 'clother', 'name', 'outwear_type', 'size')
As I understand that read_only fields let me add or edit Outwear object further, but I supposed to have 2 types of permition:
All users can see only active Commodity objects.
Only Companies can create and edit their own objects.
Do I need to make 2 Serializer Models for read_only=True/False?
What is the best practice and where can I find good examples of something familiar?
I call User - unauthorized User. Company is authorized User.
Thanks!
For your first question:
class CommoditySerializer(ModelSerializer):
class Meta:
model = Commodity
fields = (shop, price)
Class CommodityActiveAPIView(generics.ListAPIView):
serializer_class = serializers.CommoditySerializer
queryset = Commodity.objects.filter(active=True)
second question is ambiguous. first define user role please
I have the Model1 of app1
class Event(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500)
eventdate = models.DateField()
created = models.DateTimeField(auto_now_add=True)
Model 1 of app2
class Register(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
select_the_event = models.ManyToManyField(Event)
created = models.DateTimeField(auto_now_add=True)
Event database contain event information for one complete year.
How to populate the "select_the_event" with list of selected events that are valid for next 60 days?
If you are have forms.py for the Register model, then inside the RegisterForm class you can add attribute
class RegisterForm(forms.ModelForm):
....
....
select_the_event = forms.ModelMultipleChoiceField(queryset=Event.objects.filter(
event_date__range=[datetime.datetime.now().date(), datetime.datetime.now().date() + datetime.timedelta(60)])
)
In your ModelForm, assign a custom queryset to the ModelMultipleChoiceField for select_the_event:
select_the_event = forms.ModelMultipleChoiceField(
queryset=Event.objects.filter(...))