I have been working on an e-commerce website for a while. There three types of products there: Clothes, Accessories and Shoes. There is item table and category table. In the category table are the category objects(clothes,accessories, shoes) which maybe in the near future won't be changed. In my case i don't want accessories to have sizes. So when i am rendering the templates i do if statement which checks if the item's category is accessory. If it is I don't render the size field's value(which is null). Everything works good but i think that there is a better way to achieve this functionality without hard coding the if statement. Can you give me an advice for improving the code?
models.py
class ItemCategory(models.Model):
category = models.CharField(max_length=20)
class Item(models.Model):
seller = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
category = models.ForeignKey(ItemCategory, on_delete=models.SET_NULL, null=True)
brand = models.ForeignKey(Brand, on_delete=models.SET_NULL, null=True)
price = models.IntegerField(null=True, blank=True)
price_negotiable = models.BooleanField(default=False)
discount_price = models.IntegerField(null=True, blank=True)
size = models.ForeignKey(Size, on_delete=models.SET_NULL, null=True, blank=True)
condition = models.CharField(choices=CONDITION_CHOICES, max_length=9)
description = models.CharField(max_length=500)
{% if item.category.category != 'accessories' %}
Size: {{ item.size.size }}
{% endif %}
That approach looks normal to me. You could also just not pass any size data for accessories in the backend too. Either way you would need to sort the data in front-end or backend as you are trying to achieve it. If you will have to exclude more than one item than accessories in future, you might want to move your checks into backend. Then you can use list to store all excluded categories and check if item is in the list
if category not in category_exclusion_list:
# do something
Generally you would want complex data filtering or processing to happen in the Backend. Especially because it will be cleaner, easier to read and plus it will support more functionalities, plus python jinja2 does not support everything python does iirc.
Related
I have to implement a newsfeed for an application where I need to show different types of content. And in the future, some new types of content may come. I have the following idea in my mind at a high level. At this point of time, I'm not concerned about ranking, caching, etc. My focus is to generate newsfeeds having different types of content.
class ContentType1(models.Model):
pass
class ContentType2(models.Model):
pass
class ContentType3(models.Model):
pass
class Content(models.Model):
c_type = models.CharField(
max_length=6,
choices=[
('TYPE1', 'Type 1 content'),
('TYPE2', 'Type 2 content'),
('TYPE3', 'Type 3 content')
]
)
type_1 = models.ForeignKey(ContentType1, null=True, blank=True)
type_2 = models.ForeignKey(ContentType2, null=True, blank=True)
type_3 = models.ForeignKey(ContentType3, null=True, blank=True)
The idea is to have a general Content model having separate fields for every type of content and a field named c_type which determines the type of the content and guides to access the corresponding field. And responding to users' requests from the Content queryset.
I'm not fully satisfied with the approach, looking for a better approach maybe something with polymorphism or any better approach using Django.
I think you can use the choices field to select the content type.
for example:
class Content(models.MOdel):
CONTENT_TYPE=(
('type1','Type1'),
('type2','Type2'),
('type3','Type3'),
)
#other fields
content_type=models.CharField(max_length=20,choices=CONTENT_TYPE,default='type1')
body = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
Sorry if the title is a bit unclear, I am a beginner and I have a few questions about database design.
I am building django app that would store info about a Book and another class Category that contains a list of genres. I would like to connect these tables so that one could choose category when inserting the book, however the categories are not showing up (I'm using django forms). Do you maybe know why?
CATEGORIES = (('Thriller', 'Thriller'), ...)
class Category(models.Model):
name = models.CharField(max_length=40, choices=CATEGORIES, default='Unknown')
class Book(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=200)
.......
category = models.ForeignKey(Category, on_delete=models.CASCADE)
Or should I just include category inside the Book class and not connect them with ForeignKey? What would be the pros and cons of this? I already changed my DB few times splitting things up and again just putting it back to Book class as I don't really know what is better design in this situation.
Thanks
NOTE I am not necessarily asking for code to build this, just ideas on how to do this. Links and blog posts for pointers are welcome.
I am building a rest api.
I have a model
class Showcase(models.Model):
title = models.CharField(max_length=50)
description = models.TextField(null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, related_name="Showcases")
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=255, unique=True)
def __str__(self):
return self.title
I am trying to build a functionality where the user that created a showcase can add users that contributed to the project which is the showcase. I was thinking of making this its own model like this:
class Collaborator(models.Model):
post = models.ForeignKey(Showcase, on_delete=models.CASCADE, related_name="collaborated_showcases")
owner = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, related_name="showcase_owner")
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, related_name="collaborators")
skill = models.ForeignKey(Skill, on_delete=models.CASCADE, null=True, related_name="creative_type")
role = models.TextField(null=True)
added_on = models.DateTimeField(null=True)
def __str__(self):
return f"{self.user.name} collaborated on {self.post.name}"
The user would have to search for users and then add them as a contributor to the showcase, which is where my brain scrambles a bit.
The other important thing is that I want to be able to randomly go to a user and get ALL the showcases he has contributed to.
As I see it, this structure works fine for your use case, though:
models should always be in singular case (Collaborator)
related_names should be lower case (related_name="showcases")
and I prefer to explicitly spell out all related_names, so I'd add
Collaborator.post related name collaborated_showcases
Collaborator.user related name collaborators
Showcase.user related_name owned_showcases
Then,
To find an user's owned showcases, Showcase.objects.filter(user=user)
To find an user's collaborated showcases, Showcase.objects.filter(collaborators=user) (I think)
I'd suggest having a Collaborator object for the owner user as well, so you can show their role more easily as well as make these queries simpler.
I have three models, I want to display users who apply for leave but I don't know how to accomplish that. The relationship between user to new leave is one to many and the leave balance to new leave is many to many and user to balance is one to one. I only want to display data from user and new leave.
class newleave(models.Model):
user=models.ForeignKey(User,default='',on_delete=models.CASCADE)
leave_balance=models.ManyToManyField(Leave_Balance)
leave=(
('annual','annual'),
('sick','sick'),
)
Leave_type=models.CharField(max_length=100,choices=leave,blank=False,default='')
dp=(
('test','test'),
('test1','test1'),
)
department=models.CharField(max_length=100,choices=dp,blank=False,default='')
Start_Date=models.DateField(null=True, blank=False, default=None)
End_Date=models.DateField(null=True, blank=False, default=None)
Total_working_days=models.FloatField(null=True, blank=False, default=None)
def __unicode__(self):
return self.Leave_type
class Leave_Balance(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,)
Outstanding_balance=models.FloatField(null=True, blank=True, default=None)
Monthly_entitlement=models.FloatField(null=True, blank=True, default=None)
Monthly_consumption=models.FloatField(null=True, blank=True, default=None)
Leave_current_balance= models.FloatField(null=True, blank=True, default=None)
Month=models.CharField(max_length=100,default="",null=True)
Year=models.CharField(max_length=100,default='')
def __unicode__(self):
return self.Year
The simple way to get users that have an entry in the newleave table is
User.objects.filter(newleave_set__isnull=False).distinct()
I would suggest following PEP8 for your code style as it allows programmers familiar with Python to quickly pick up the intentions of the programs that you write.
Class names should use the CapsWord convention - class NewLeave class LeaveBalance
Method names and instance variables should be lowercase words seperated by underscores NewLeave.start_date etc
The solution was quite straight forward but it took me a while to figure it out. I access the User models data via foreign key and Django actually took care of the joins.
views.py
def Allleaves(request):
allleave=NewLeave.objects.all()
return render(request,'allleave.html',locals())
and in the allleave.html, i access the the User info through the foreign key "user"
{% for leave in allleave%}
{{leave.user.first_name}}
{{leave.user.last_name}}
{{leave.Leave_type}}
{{leave.department}}
{%endfor%}
I'm working on a fairly simple library project in Django, here are my models, a book can have many copies and each copy can have many loans.
class Author(models.Model):
name = models.CharField(max_length=200, unique=True)
class Book(TimeStampedModel):
isbn = models.CharField(max_length=13, primary_key=True)
title = models.CharField(max_length=200, db_index=True, unique=True)
authors = models.ManyToManyField('Author', related_name='books')
#property
def is_available(self):
"""Returns True if the Book has any available copies"""
return self.copies.exclude(loans__returned=False).exists()
class BookCopy(models.Model):
book = models.ForeignKey('Book', related_name='copies')
class Loan(models.Model):
start_date = models.DateField()
end_date = models.DateField()
returned = models.BooleanField(default=False)
customer = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
null=True, related_name='loans')
book_copy = models.ForeignKey(
'BookCopy', on_delete=models.CASCADE, related_name='loans')
I have a fairly simple view containing a list of books
def book_list(request):
book_list = Book.objects.prefetch_related('authors', 'copies__loans')
return render(request, 'books/book_list.html', {'books': books})
To figure out if a book is available I've written the property is_available inside the Book model. However when I call this property inside my template with the following:
{% for book in books %}
{% if not book.is_available %}
-- Template stuff --
{% endif %}
{% endfor %}
According to Django Debug Toolbar I end up with a duplicate query for every Book in the queryset
Reading the Django documentation for prefetch related there's a section discribing the behaviour which I think may be the culprit
Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query.
How would I prevent these duplicate queries from occuring?