Im new to django and im currently making an admin panel where i can view user orders.
I handle my orders based on the following OrderItem Model
class OrderItem(models.Model):
customer = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
product = models.ForeignKey(
Product, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
and their shipping info in the follwing ShippingAdress model
class ShippingAddress(models.Model):
customer = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
address = models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
Views.py
orders=OrderItem.objects.select_related('customer')
context={
'orders':orders,
}
return render(request, 'index.html', context)
and in my html i want to print each customer's ShippingAdress data.
Im thinking something like the following but im stuck and it doesnt work.
{% for order in orders %}
<td>{{order.customer.address}}</td>
<td>{{order.customer.city}}</td>
{% endfor %}
What is the correct way to achieve this?
Add related_name to your ShippingAddress
class ShippingAddress(models.Model):
customer = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True, related_name="addresses")
and use it in your template like that
<td>{{order.customer.addresses.first.address}}</td>
with first you get the first address and with all all of them.
Related
I have a model in my Django application for review. This model has two foreign keys to the product and user models. But when I go to the admin panel and try to add a new review I don't see the review models dropdown select for the foreign keys.
I'm expecting to see the foreign keys fields rendered in my admin panel as dropdown selects like in the blue box in the picture below.
Screenshot of my admin panel to add a new order object
But the admin panel doesn't show those fields. It only shows the name, rating, and comment fields.
Screenshot of my admin panel to add a new reivew object
Here is my review model.
class Reviews(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True),
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True),
name = models.CharField(max_length=350, null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)
In your Reviews model, you have put a comma at the end of users and product fields. Remove the trailing comma at the end, as the fields are considered as tuple when a comma is present.
It should be:
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
Also, your createdAt field is not correct.
It should be:
createdAt = models.DateTimeField()
Try it like this, i removed comma from user and product field in the end, also i have added () in DateTimeField
class Reviews(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=350, null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField()
I have tried using the following to regroup a ListView queryset in my template so that objects are grouped by a related field's value:
<div class="grid grid-cols-4">
{% regroup object_list by related_field.sort_value as grouped_list %}
{% for group in grouped_list %}
<div class="border-2 border-black">
<span>... {{group.grouper}} ...</span>
{% for item in group.list %}
<p>{{item.related_field.name}}</p>
<p>{{item.description}}</p>
{% endfor %}
</div>
{% endfor %}
</div>
The model has about a dozen fields, two of them relational (first related model has a couple dozen fields, the other has just a few) and there's several hundred total objects in the ListView queryset results.
View:
class BigListView(ListView):
model = MyModel
template_name = 'my_model/big_list_view.html'
def get_queryset(self):
return MyModel.objects.order_by('related_model_b.sort_value')
Models:
class MyModel(models.Model):
code = models.CharField(max_length=30, unique=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
sale_price = models.DecimalField(max_digits=8, decimal_places=2)
sale_price_quantity_3_5 = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
sale_price_quantity_6 = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
description = models.CharField(max_length=40)
location = models.CharField(max_length=20)
quantity_on_hand = models.IntegerField()
size = models.CharField(max_length=20)
tag_description = models.CharField(max_length=100)
color = ColorField(help_text='Theme Color')
image = models.ImageField(upload_to=assign_product_sku, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
related_model_a = models.ForeignKey(RelatedModelA, related_name='mymodels', on_delete=models.CASCADE)
related_model_b = models.ForeignKey('RelatedModelB', related_name='mymodels', on_delete=models.CASCADE, blank=True, null=True)
class RelatedModelA(index.Indexed, models.Model):
sku = models.CharField(max_length=20, unique=True)
name = models.CharField(max_length=100)
alt_name = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
age = models.CharField(max_length=3, blank=True)
size = models.CharField(max_length=100, blank=True)
weight = models.CharField(max_length=100, blank=True)
shape = models.CharField(max_length=100, blank=True)
style = models.CharField(max_length=100, blank=True)
rate = models.CharField(max_length=100, blank=True)
attribute_a = models.CharField(max_length=100, blank=True)
attribute_b = models.CharField(max_length=100, blank=True)
attribute_c = models.CharField(max_length=100, blank=True)
attribute_d = models.CharField(max_length=100, blank=True)
attribute_e = models.CharField(max_length=100, blank=True)
attribute_f = models.CharField(max_length=100, blank=True)
attribute_g = models.CharField(max_length=100, blank=True)
attribute_h = models.CharField(max_length=100, blank=True)
attribute_i = models.CharField(max_length=100, blank=True)
attribute_j = models.CharField(max_length=100, blank=True)
attribute_k = models.CharField(max_length=100, blank=True)
attribute_l = models.CharField(max_length=100, blank=True)
attribute_m = models.CharField(max_length=100, blank=True)
attribute_n = models.CharField(max_length=100, blank=True)
attribute_o = models.CharField(max_length=100, blank=True)
attribute_p = models.CharField(max_length=100, blank=True)
attribute_q = models.CharField(max_length=40, blank=True)
attribute_r = models.CharField(max_length=100, blank=True)
attribute_s = models.CharField(max_length=100, blank=True)
comment = models.CharField(max_length=100, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
image_url = models.URLField(blank=True)
slug = models.SlugField(max_length=100, blank=True)
tags = TaggableManager(blank=True)
class RelatedModelB(models.model):
code = models.CharField(max_length=30, unique=True)
sort_value = models.IntegerField()
last_retrieved = models.DateTimeField(auto_now=True)
json_data = models.JSONField(blank=True, null=True)
Viewing this on local/dev machine has no problems, but hitting the view on production Heroku it crashes the app because of excess memory usage (~2GB). The app is currently running on Hobby (512MB) and while I will likely bump this up to Standard 1x/2x, that's still well short on memory unless I go up to a higher performance dyno which is overkill with the exception of this single view.
What can I do to reduce this view's memory usage?
For starters you access related_field (related_model_b/related_model_a?) for each item in your queryset which is performing a DB query each time, use select_related() to fetch the related data in a single query
MyModel.objects.select_related('related_model_b', 'related_model_a').order_by(...)
Because you already sort by related_field.sort_value you can get away with using the ifchanged tag instead of regroup if regroup is a massive problem
{% for item in object_list %}
{% ifchanged item.related_field.sort_value %}<span>{{ item.related_field.sort_value }}</span>{% endifchanged %}
<p>{{item.related_field.name}}</p>
<p>{{item.description}}</p>
{% endfor %}
I ended up with a combination of Iain's suggestion to use selected_related and also using defer() to exclude some of the fields in my related models that aren't necessary for this view.
Specifically, I believe (but haven't tested) that the JSONField attached to a related model is the culprit, as this field normally holds just a couple kB of data, but in some cases it's holding ~400kB.
I changed the queryset in my view to the following:
class BigListView(ListView):
model = MyModel
template_name = 'my_model/big_list.html'
def get_queryset(self):
return MyModel.objects.select_related('related_model_a','related_model_b').order_by('related_model_b__sort_value').defer(
'related_model_b__json_data',
... additional fields ...
)
Original memory usage was nearly 2gB.
Using select_related only reduced that to ~800mB.
Using select_related and defer() reduced it down to ~200mB, which is no different than the app typically uses for any given operation.
Please I have a project where I want to hide some fields in a form when the category selected belongs to a particular product type. The type of products is Single and Bundle products. So for instance, if I choose something like pens(Bundle) in the form category I should only see quantity in the form fields but if I select something like Desk(single) all fields should be available to fill. How do I implement this in Django? Thank you
My Model
TYPE =(('Single', 'Single'),('Bundle','Bundle'))
class Category(models.Model):
name = models.CharField(max_length=50, blank=True, null=True)
pro_type = models.CharField(max_length=50, choices=TYPE, null=True)
timestamp = models.DateTimeField(auto_now_add=False, auto_now=True, null=True)
def __str__(self):
return f'{self.name}'
class Product(models.Model):
pro_name = models.CharField(max_length=100, blank=True, null=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
quantity = models.IntegerField(default='0', blank=True, null=True)
issue_to = models.ForeignKey('Order',default='', on_delete=models.CASCADE,blank=True, null=True)
serial_num = models.CharField(max_length=100, blank=True, null=True)
model_num = models.CharField(max_length=100, blank=True, null=True)
storage_size = models.CharField(max_length=50, blank=True, null=True)
My views
def add_products(request):
form = ProductCreateForm(request.POST)
if request.method == 'POST':
if form.is_valid():
obj = form.save(commit=False)
obj.staff = request.user
obj.save()
return redirect('dashboard-products')
else:
form = ProductCreateForm()
context = {
'form': form,
}
I have many to many field in user model where one user can have multiple roles for example admin, patient, doctor and others. now I want to query data to get users with admin and all other roles and not doctor and patient role. I am using this
User.objects.exclude(roles__code_name__in=['pt', 'doc'])
now my one user signs up as patient too so he has admin and patient role both now i am unable to get him by using above query. so concluding... if user has two roles if one of it is patient and he has any other role too i want to get him too. what should i do? Thanks in advance
UPDATE
class User(AbstractBaseUser):
username = models.CharField(max_length=30, unique=True)
email = models.EmailField(max_length=60, blank=True, null=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
cnic = models.CharField(max_length=13, unique=True)
mobile = models.CharField(max_length=11, unique=True)
dob = models.DateField(blank=True, null=True)
full_name = models.CharField(max_length=90, blank=True, null=True)
profile_image = models.ImageField(max_length=255, upload_to=get_profile_image_path, null=True, blank=True, default=get_default_profile_image_path)
next_of_kin_name = models.CharField(max_length=60, blank=True, null=True)
next_of_kin_mobile = models.CharField(max_length=11, blank=True, null=True)
is_delete = models.BooleanField(default=False)
status = models.IntegerField(default=0)
contact = models.CharField(max_length=10, blank=True, null=True)
hospital = models.ForeignKey('Hospital', on_delete=models.SET_NULL, blank=True, null=True)
roles = models.ManyToManyField('Role', related_name='users')
is_staff = models.BooleanField(default=False)
balance = models.PositiveIntegerField(default=0)
gender = models.CharField(max_length=10, choices=gender_choices, default=gender_choices[0][0])
phone_verified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey('self', related_name='+', blank=True, null=True, on_delete=models.CASCADE)
updated_at = models.DateTimeField(auto_now=True)
updated_by = models.ForeignKey('self', related_name='+', blank=True, null=True, on_delete=models.CASCADE)
This is my model it has roles as many to many field. i have multiple roles like doctor, patient, admin and many others custom created roles with custom permissions. I have a view where i want to get data of users that are not patients or doctors. everything was working fine until one of my admin user decides to sign up as patient so he has now both patient and admin role and now i am unable to get him by using above mentioned query
Eureka. This solution is working fine for me idk if it's the ideal approach bit is working at the moment. Thanks #all
User.objects.annotate(num_roles=Count('roles')).exclude(Q(id=self.request.user.id) | Q(is_delete=True) | Q(roles__code_name__in=['pt', 'doc', 'su']) & Q(num_roles=1)).order_by('-id')
Hello everyone I'm trying top build a task manager web app using django, I need to assign task to one or multiple users I'm using manytomany relation in models.py and in views.py I'm adding created_by user automatically.
My problem is that when I do that I see that no users selected in assigned users but if I add created by user from the form it worked well.
class Task(models.Model):
task_id = models.AutoField(primary_key=True)
shortcode = models.CharField(max_length=15, unique=True, blank=True, null=True)
task_name = models.CharField(max_length=200)
task_progress = models.ForeignKey(TaskProgressStatus, on_delete=models.CASCADE, blank=True, null=True)
customer_name = models.ForeignKey(Customer, on_delete=models.CASCADE, blank=True, null=True)
task_priority = models.ForeignKey(TaskPriority, on_delete=models.CASCADE)
assigned_to_employee = models.ManyToManyField(User)
paid = models.BooleanField(default=False)
on_account = models.BooleanField(default=False)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE, blank=True, null=True)
net_amount = models.DecimalField(decimal_places=2, max_digits=20, blank=True, null=True)
vat = models.IntegerField(default=11)
quote_validity = models.CharField(max_length=200, default='1 Month from offer date')
delivered = models.BooleanField(default=False)
delivered_date = models.DateTimeField(null=True, blank=True)
creation_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
due_date = models.DateTimeField(null=True, blank=True)
created_by = models.ForeignKey(User, related_name='created_by_username', on_delete=models.CASCADE, null=True, blank=True)
project = models.ForeignKey(Project, null=True, blank=True, on_delete=models.CASCADE)
file_name = models.FileField(upload_to='projects_files', null=True, blank=True)
notes = models.TextField()
def __str__(self):
return str(self.task_name)
#login_required
def addtask(request):
form = taskForm()
if request.method == 'POST':
form = taskForm(request.POST)
if form.is_valid():
newform = form.save(commit=False)
newform.created_by = request.user
newform.save()
return HttpResponseRedirect(request.path_info)
else:
context = {'form':form}
return render(request, 'tasks/add_task.html', context)
Update
As well pointed out by Ahmed I. Elsayed there is some inconsistency in the title of the question, since the created_by field is actually a ForeignKey, not a ManyToManyField.
That being said, your issue is actually with the foreign key.
My suggestion is to first of all be sure that your form is actually valid. You can do that by printing something inside the if form.is_valid() block.