Django admin - Allow inline entires once selected item - django

I am trying to populate a dropdown in the Django admin panel based on a selected item.
I have a customer model
class Customer(BaseModel):
name = models.CharField(max_length=128)
company = models.ForeignKey("Company", models.PROTECT)
def __str__(self) -> str:
return f"{self.name}"
def save(self, **kwargs):
return super().save(**kwargs)
An invite model
class Invite(BaseModel):
full_name = models.CharField(max_length=128, blank=True)
email = WIEmailField(unique=True)
customer = models.ForeignKey(
to="Customer",
on_delete=models.PROTECT,
related_name="invites",
)
Customer Invite model that defines the invite and customer
class CustomerLocationInvite(BaseModel):
location = models.ForeignKey(
to=Location
)
invite = models.ForeignKey(
to=Invite,
blank=True,
)
Location Model
class Location(BaseModel):
name = models.CharField(max_length=128)
company = models.ForeignKey(
to= Company,
on_delete=models.PROTECT
)
address = models.CharField(max_length=128)
Inline for invite
class CustomerInviteInline(admin.TabularInline):
model = CustomerLocationInvite
fields = ("invite", "location", "created_at", "modified_at")
readonly_fields = ("created_at", "modified_at")
extra = 0
When creating a new Invite, Is it possible to:
Display the inline once a company has been selected?
When selecting a location from the inline, Filter out the locations based on the company they selected?

I assume you want to get the location from CustomerLocationInvite, and get the company from the location? If that is so, maybe you can try
CustomerLocationInvite.objects.filter(location__id=locationid)
Where the location's id can be received by
locationid = Location.objects.filter(company__id=companyid).id
But then since you said that the company is already selected, you should have its ID -- that is the value you will replace companyid with. You can then retrieve the inline admin from the CustomerLocationInvite object that you received in the first line.
SO reference
Doc reference
I'm not sure what you mean. Are you getting the list of companies, or are you getting the list of locations? That being said, please paste your Company model as well.

Related

Relationships in Django - how to filter data

I've looked at a lot of entries and I know how to filter simple relationships. Unfortunately, I'm stuck and I don't know how to filter my table data when one of the tables is a branch of a certain string.
models.py
from django.contrib.auth.models import User
class Autor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
description = models.TextField(blank=True, null=True)
class Incident(models.Model):
group_no = models.ForeignKey(Group, on_delete=models.CASCADE, default=1)
description = models.TextField(blank=True, null=True)
deleted = models.BooleanField(default=False)
class Department-leader(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="leader")
department = models.ForeignKey(Group, on_delete=models.CASCADE)
class Group(models.Model):
group_no = models.CharField(max_length=40, unique=True)
active = models.BooleanField(default=True)
views.py
def get_author(user):
qs = Autor.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
def show_all(request):
show_all_records = Incident.objects.filter(deleted=False).order_by('-id')[:300]
if request.user.is_authenticated:
autors_list = get_author(request.user)
user_list = get_user_model()
logged_user = get_object_or_404(user_list, username__exact=autors_list)
(...)
print("Logged user: " + str(logged_user.id))
else:
logged_user = ""
context = {
'show_all_records': show_all_records,
'logged_user': logged_user,
}
return render(request, 'incident/all_records.html', context)
The show_all_records variable represents all the records of the Incident table and that is ok.
The second thing I would like to display are entries for the logged in person i.e. all incidents in particular departments of the leader who is logged in.
If the tables were connected linearly, I would have no problem building this filter.
But how to make a filter for this layout of tables?
In pure SQL, it would look something like this:
select
bledy_bledy.nr_zlecenia,
bledy_bledy.ilosc_bledow,
bledy_gruparobocza.nr_grupy,
auth_user.username,
auth_user.id
from
bledy_bledy
LEFT JOIN
bledy_lider_dzial
on
bledy_bledy.nr_grupy_roboczej_id = bledy_lider_dzial.dzial_id
LEFT JOIN
bledy_gruparobocza
on
bledy_lider_dzial.dzial_id = bledy_gruparobocza.id
LEFT JOIN
auth_user
on
bledy_lider_dzial.user_id = auth_user.id
where
auth_user.id = 4
**Can I count on some hint on how to build it?**
I think this may be what you want.
user = request.user
# only need the primary keys of the group leaders for the next query
department_ids = user.leader.all().values_list('department_id', flat=True)
incidents = Incident.objects.filter( group_no_id__in= departments )
Also a suggestion: stick to Django conventions for naming foreign keys and related names. leaders not leader (because it refers to a plurality or set of leaders), and group not group_no because it refers to a Group object. (The actual FK/primary key value is obtained by appending _id to the field name, as used in the above. This is Django "magic".)

Django ORM Query Optimization Issue

I am making a blog website and I am facing some issues with the Query performance.
I have 3 models
User Model -> Users (To store user email, Password etc)
Post Model -> Actual Posts
people Model -> (To store users extra information)
Post Model ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
title = models.CharField(max_length=255,null=True)
description = models.CharField(max_length=1000,null=True)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
favourites = models.ManyToManyField(to=User,blank=True,related_name="favourite")
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
Now as both of these models are connected to User model. I want to query the Post model and get the user photo in the template. Now when I use post.user.people.photo then for every post it generates a seperate query to DB resulting in slowness. I would like to use Join here to combines multiple tables and fetch all the records at once.
I am currently using following Query ->
posts = Post.objects.select_related().prefetch_related('images_set').annotate(comments_Count = Count('comments_post',distinct=True)).annotate(Count('Likes',distinct=True)).all().order_by('-id')
You can perform a .select_related(…) [Django-doc] on the user and the people with user__people, so:
posts = Post.objects.select_related(
'user__people', 'category'
).prefetch_related('images_set').annotate(
comments_Count = Count('comments_post',distinct=True),
Count('Likes',distinct=True)
).order_by('-id')
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

how can each user get increment and unique id on same table in django

Each time i want to add an invoice, i want to have a unique invoice_id which is an increment number (+1), but the problem is that i have a multiple users app, so i get the error that this invoice_id already exist. how can i customize the ids so each user can have its ids following the latest of same user.
class Company(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
class Invoice(models.Model):
company = models.ForeignKey('Company', on_delete=models.CASCADE)
invoice_id = models.CharField(max_length=20, unique=True)
name = models.CharField(max_length=256)
add an last_invoice field in your company record. Then let it do the work for you by adding a function that generates new invoice:
class Company(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
last_invoice = models.CharField(max_length=20)
def get_invoice(self):
l_newNum = self.last_invoice + '1' #your number here
self.last_invoice = l_newNum
self.save()
return l_newNum
class Invoice(models.Model):
company = models.ForeignKey('Company', on_delete=models.CASCADE)
#you no longer need unique as it will create a mess between companies
invoice_id = models.CharField(max_length=20)
name = models.CharField(max_length=256)
def save(self):
self.invoice_id = self.company.get_invoice()
super(Invoice,self).save()
You need to fill in the details here and there, but this should work for you. IDeally I would suggest that the get_invoice is actually used to automatically create Invoice entry for the company, but this would depend on the concrete case you are building.

Django: Problem with saving model instances with ForeignKey-relation to database

I would like to create and save model instances with Django.
These are my models:
class Customer(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
...
class Order(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
comment = models.TextField()
...
I create an order like this:
def store_storage_space_order(cleaned_data):
try:
user = User.objects.create_user(
cleaned_data["customer_email"],
cleaned_data["customer_email"],
1234
)
customer = Customer.objects.create(
user=user,
first_name=cleaned_data["customer_firstname"],
last_name=cleaned_data["customer_lastname"],
email=cleaned_data["customer_email"],
phone_number=cleaned_data["customer_phone"]
)
StorageSpaceOrder.objects.create(
customer=customer,
order_price=Decimal(cleaned_data["order_price"])
)
except Exception as exc:
logger.exception("Couldn't store any order information", exc, cleaned_data)
As far as I've learned, Django will save the object on calling create as well.
Trying to save the order, I get the following error message:
save() prohibited to prevent data loss due to unsaved related customer
What I don't get; customer is already there and saved in the database. There are no changes on the customer in between.
Also, I've tried customer_id=customer.id/pk, - but both ID and PK return None.
Why is this and what do I need to change? Loading the object again is not the preferred way, as I only got the ID which marks it as unique.
Thanks for your input :)
ID fields have to be auto-generated by Django, so you don't need to declare them in your models.
If you do, you override the default behaviour called when an instance of this model is created/saved.

django display reverse m2m in admin including null

I'm trying to display the reverse M2M relationship in the admin i.e. for the below models, not just display for a given service the region(s) it covers, but I also want to see for a given region what services there are. Also the same for payment types. For the reverse views it would be good to see what null entries, e.g. in payment types click on null and see what services have not been assigned payment types yet. (I seem to have this in some services even though I haven't specified null=true in the ManytoManyField declarations, - not sure if M2M fields allow this by default?)
class Service(models.Model):
name = models.CharField(max_length=255)
supplier = models.ForeignKey(Supplier)
payment_methods = models.ManyToManyField(PaymentMethod)
region = models.ManyToManyField(Region)
class Region(models.Model):
unique_id = models.IntegerField(unique=True)
name = models.CharField(max_length=255, blank=True)
def __str__(self):
return str(self.unique_id)
class PaymentMethod(models.Model):
MONTHLY_DIRECT_DEBIT = 'MDD'
CASH_OR_CHEQUE = 'CAC'
QUARTERLY_DIRECT_DEBIT = 'QDD'
PAYMENT_CHOICES = (
(MONTHLY_DIRECT_DEBIT, 'Monthly Direct Debit'),
(CASH_OR_CHEQUE, 'Cash or Cheque'),
(QUARTERLY_DIRECT_DEBIT, 'Quarterly Direct Debit'),
)
unique_id = models.CharField(max_length=3, choices=PAYMENT_CHOICES)
name = models.CharField(max_length=255, unique=True)