django charge users based on how many counties they want to access - django

I'm building a web app,
basically I currently have 3 models ,
1- State: which represents all US states
2- County: which represents all counties with foreign key of state
3- Home: which represents all homes with foreign key of County
the app will show homes,
but users needs to subscribe for certain counties (the counties prices can vary)
the goal is : when users subscribe to certain counties they can see the related "Homes" to these counties
I'm not sure how should I represent these relations between users, subscriptions and how to connect it to County model I have.
and how to make a view for the user to add new counties.
Thank you.
Update (My models):
class State(models.Model):
state_name = models.CharField(max_length=50)
def __str__(self):
return self.state_name
class County(models.Model):
county_name = models.CharField(max_length=50)
state = models.ForeignKey(State, on_delete=models.CASCADE)
def __str__(self):
return self.county_name
class Meta:
unique_together = ("county_name", "state")
verbose_name_plural = 'Counties'
class Home(models.Model):
owner_name = models.CharField(max_length=100, null=True, blank=True)
street_address = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=50, null=True, blank=True)
county = models.ForeignKey(County, on_delete=models.CASCADE)
postal_code = models.CharField(max_length=50, null=True, blank=True)
price = models.CharField(max_length=50, null=True, blank=True)
sqft = models.CharField(max_length=50, null=True, blank=True)
home_type = models.CharField(max_length=100, null=True, blank=True)
geom = models.PointField()
added = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '{}, {}, {}'.format(self.street_address, self.city, self.county.state.state_name)
class Meta:
verbose_name = 'Home'
verbose_name_plural = 'Homes'
#property
def state_county(self):
return f'{self.county.county_name}_{self.state}'
#property
def state(self):
return self.county.state.state_name

Here is a basic idea, you should evaluate from this point.
class State(models.Model)
name = models.CharField(max_length=100)
class County(models.Model)
state = models.ForeignKey(State)
name = models.CharField(max_length=100)
class Home(models.Model)
county= models.ForeignKey(County)
name = models.CharField(max_length=100)
class Subscription(models.Model)
county = models.ForeignKey(County)
user = models.ForeignKey(User)
Basically, you can then charge your user per County (observe that one can have more than one County subscription)
Another aproach would be to use a hierarchy to have State>County>Home, on a MPTT, but maybe its not what you want.

One way would be to add ManyToMany County relationship field in the Subscriptions model and then you would query subscribed county and filter Home.
Something in the sense of:
class County(models.Model):
county = models.CharField(max_length=255)
class Home(models.Model):
county = models.ForeignKey(County, on_delete=models.PROTECT)
class Subscription(models.Model):
user = models.ForeingKey(User, on_delete=models.PROTECT)
county = models.ManyToMany(County)
Then you'd query subscriptions and filter based on that.
subscriptions = Subscription.objects.filter(user=request.user).values_list('county', flat=True)
homes = Home.objects.filter(county_id__in=subscriptions)
You could further improved that with models Manager on Subscription to avoid filtering user every time with something like:
class SubscriptionManager(models.Manager):
def user_subscriptions(self, user):
return super().get_queryset().filter(user=user)
class Subscription(models.Model):
user = models.ForeingKey(User, on_delete=models.PROTECT)
county = models.ManyToMany(County)
objects = SubscriptionManager()
and then filter either with:
subscriptions = Subscription.objects.filter(user=request.user).values_list('county', flat=True)
or
subscriptions = Subscription.objects.user_subscriptions(request.user).values_list('county', flat=True)

Related

How to make a query across multiple models in Django

I'm using Django and I want to know how to get objects through 3 models
These are my models
class Participant(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
is_leader = models.BooleanField(default=False)
team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, related_name="participants")
application_date = models.DateField(auto_now_add=True, null=True)
resolution_date = models.DateField(null=True, blank=True)
accepted = models.BooleanField(default=False)
class Team(models.Model):
name = models.TextField(default="")
is_public = models.BooleanField(default=False)
institution = models.ForeignKey(Institution, on_delete=models.CASCADE, null=True, related_name='teams')
campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE, null=True, related_name='teams')
class Campaign(models.Model):
name = models.TextField(default="")
description = models.TextField(default="")
initial_date = models.DateTimeField(auto_now_add=False, null=True, blank=True)
end_date = models.DateTimeField(auto_now_add=False, null=True, blank=True)
qr_step_enabled = models.BooleanField(default=True)
image_resolution = models.IntegerField(default=800)
sponsor = models.ForeignKey(Sponsor, on_delete=models.CASCADE, null=True, related_name='campaigns')
I have the user through a request, and I want to get all campaigns of that user.
I tried doing it with for loops but I want to do it with queries
this is what I had:
user = request.user
participants = user.participant_set.all()
for participant in participants:
participant.team.campaign.name
is there a way to make a query through these models and for all participants?
A user can have many participants, and each participant has a Team, each team has a campaign
The best way is to merge the two modela Team and Campaign in one model.
Something as simple as this should work:
Campaign.objects.filter(team__participant__user=request.user)
The Django ORM is smart enough to follow foreign key relationships in both directions.
Thanks to Daniel W. Steinbrook to guide me to the answer, I had to do this to get the query:
Campaign.objects.filter(teams__participants__user__exact=request.user)

How do I show only a subset of options in a Django dropdown menu

I have an app that allows users to signup and register for courses (from a 'TrainingInstance' model). These events have names etc and are categorised as Past or Current in the database (in the 'Training' model). When I show the BuildOrderForm in my template, I want only options for Current trainings to be shown in the dropdown menu. How can this be done in Django without javascript or Ajax?
I have the following form in forms.py:
class BuildOrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['training_registered']
And the following models in models.py:
class Training(models.Model):
""" Model which specifies the training category (name) and whether they are Past or Present"""
YEAR = (
('current', 'current'),
('past', 'past'),
)
name = models.CharField(max_length=200, null=True)
year= models.CharField(max_length=200, null=True, choices=YEAR, default='current')
def __str__(self):
return self.name
class TrainingInstance(models.Model):
""" Creates a model of different instances of each training ( May 2021 etc) """
name = models.CharField(max_length=200, null=True, blank=True)
venue = models.CharField(max_length=200, null=True, blank=True)
training = models.ForeignKey(Training, on_delete= models.CASCADE, null = True)
training_month = models.CharField(max_length=200, null=True, blank=True)
participant_date = models.CharField(max_length=20, null=True, blank=True)
staff_date = models.CharField(max_length=20, null=True, blank=True)
graduation_date = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class Order(models.Model):
REGSTATUS = (
('registered', 'registered'),
('enrolled', 'enrolled'),
('holding', 'holding'),
('withdrawn', 'withdrawn'),
('waiting', 'waiting'),
)
customer = models.ForeignKey(Customer, on_delete= models.CASCADE, null = True)
training_registered = models.ForeignKey(TrainingInstance, on_delete= models.SET_NULL, blank = True, null = True)
registration_date = models.DateTimeField(null=True,blank=True)
regstatus = models.CharField(max_length=200, null=True, choices=REGSTATUS, default='registered')
def __str__(self):
return self.customer.username
Here is what I have done - which works but I'm also open to feedback about good/bad practice.
class BuildOrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['training_registered']
def __init__(self,*args,**kwargs):
super (BuildOrderForm,self ).__init__(*args,**kwargs)
self.fields['training_registered'].queryset = TrainingInstance.objects.filter(training__year ="current")

Manipulate Excel Data Before Adding to Database with Django - Order of Operations?

I receive 6 weekly excel reports that I've been manually compiling into a very large monthly report. Each report has between 5-30 columns, and 4000 to 130,000 rows.
I'm putting together a simple Django app that allows you to upload each report, and the data ends up in the database.
Here's my models.py:
#UPEXCEL models
from django.db import models
############## LISTS ###############
class TransactionTypeList(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class TransactionAppTypeList(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class CrmCaseOriginList(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
############## CLIENTS AND STAFF ###############
class Staff(models.Model):
name = models.CharField(max_length=40)
employee_id = models.CharField(max_length=40)
start_date = models.TimeField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
first_name = models.CharField(blank=True, null=True, max_length=40)
last_name = models.CharField(blank=True, null=True, max_length=40)
email = models.EmailField(blank=True, null=True)
phone = models.CharField(blank=True, null=True, max_length=20)
street = models.CharField(blank=True, null=True, max_length=100)
city = models.CharField(blank=True, null=True, max_length=100)
state = models.CharField(blank=True, null=True, max_length=2)
zipcode = models.CharField(blank=True, null=True, max_length=10)
is_team_lead = models.BooleanField(default=False)
boss = models.ForeignKey('Staff', related_name='Boss', null=True, blank=True)
def __str__(self):
return self.name
class Meta:
app_label="upexcel"
class Client(models.Model):
name = models.CharField(max_length=40)
short_name = models.CharField(max_length=20, blank=True, null=True)
start_date = models.DateField(default=timezone.now, blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
team_lead = models.ForeignKey(Staff, related_name='client_team_lead')
def __str__(self):
return self.name
class ClientNameChart(models.Model):
client_name = models.ForeignKey(Client, related_name='client_corrected_name')
name_variation = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s becomes %s' % (self.name_variation, self.client_name)
class StaffNameChart(models.Model):
staff_name = models.ForeignKey(Staff, related_name='staff_corrected_name')
name_variation = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s becomes %s' % (self.name_variation, self.staff_name)
############## DATA FROM REPORTS ###############
class CrmNotes(models.Model):
created_by = models.ForeignKey(Staff, related_name='note_creator')
case_origin = models.CharField(max_length=20)
client_regarding = models.ForeignKey(Client, related_name='note_client_regarding')
created_on = models.DateTimeField()
case_number = models.CharField(max_length=40)
class Transactions(models.Model):
client_regarding = models.ForeignKey(Client, related_name='transaction_client')
created_by = models.ForeignKey(Staff, related_name='transaction_creator')
type = models.ForeignKey(TransactionTypeList, related_name='transaction_type')
app_type = models.ForeignKey(TransactionAppTypeList, related_name='transaction_app_type')
class Meta:
app_label="upexcel"
class Timesheets(models.Model):
staff = models.ForeignKey(Staff, related_name='staff_clocked_in')
workdate = models.DateField()
start_time = models.DateTimeField()
end_time = models.DateTimeField()
total_hours = models.DecimalField(decimal_places=2, max_digits=8)
class Provider(models.Model):
name = models.CharField(max_length=40)
street = models.CharField(max_length=100)
city = models.CharField(max_length=40)
state = models.CharField(max_length=11)
zip = models.CharField(max_length=10)
class StudentsApplication(models.Model):
app_number = models.CharField(max_length=40)
program = models.CharField(max_length=40)
benefit_period = models.CharField(max_length=40)
student_name = models.CharField(max_length=40)
student_empl_id = models.CharField(max_length=40)
requested_amount = models.DecimalField(max_digits=8, decimal_places=2)
provider = models.ForeignKey(Provider, related_name='app_provider')
provider_code = models.CharField(max_length=40)
class AuditReport(models.Model):
was_audited = models.BooleanField(default=False)
auditor = models.ForeignKey('upexcel.Staff', related_name='auditor')
payment_defect = models.BooleanField(default=False)
grant_discount_error = models.BooleanField(default=False)
math_error = models.BooleanField(default=False)
fees_book_error = models.BooleanField(default=False)
other_error = models.BooleanField(default=False)
overpayment_amount = models.DecimalField(max_digits=8, decimal_places=2)
underpayment_amount = models.DecimalField(max_digits=8, decimal_places=2)
doc_defect = models.BooleanField(default=False)
status_change = models.BooleanField(default=False)
admin_savings_defect = models.BooleanField(default=False)
network_savings_defect = models.BooleanField(default=False)
admin_adjustments = models.DecimalField(max_digits=8, decimal_places=2)
network_adjustments = models.DecimalField(max_digits=8, decimal_places=2)
error_corrected = models.BooleanField(default=False)
comments = models.TextField(max_length=500)
client = models.ForeignKey(Client, related_name='audited_client')
staff = models.ForeignKey(Staff, related_name='processor_audited')
application = models.ForeignKey(StudentsApplication, related_name='app_audited')
class Meta:
app_label="upexcel"
However the excel reports I'm taking in need some work done to them, and I'm trying figure out exactly how I should go about processing them and routing them.
The first challenge is that each report references the associated Staff and Client with different data. For example, if the Staff.name is "Bob Dole", one report has it as "Dole, Bob". Another has it as "Dole, Robert". Still another has "Robert Dole" then "103948210", which is his employee ID number.
Also, these change and new ones sprout up, which is why I made ClientNameChart and StaffNameChart, to where a user can input the string as it shows up in a report, and attach it to a Client or Staff. Then when processing, we can lookup StaffNameChart.name_variation, and return the associated StaffNameChart.Staff.employee_id, which should work great as a foreign key within the respective report's table (ie. AuditReport.staff)
The second challenge is to take a report, and route some of the columns to one database table, and others to another. For example, the big one is the Audit Report sheet. Many of the columns just transpose directly into the AuditReport(models.Model). However, it also has data for each StudentsApplication and Provider, where I need to take several columns, store them as a new record in their destination table, and replace the columns with one column containing a foreign key for that item within that destination table.
So that is my quest.
Here's the order of operations I have in my head - I will use the most complex Audit_Report_Wk_1.xlsx report to address all challenges in one upload:
Upload File
Using openpyxl, load read-only data:
from openpyxl.worksheet.read_only import ReadOnlyWorksheet
myexcelfile = request.FILES['file']
myworkbook = load_workbook(myexcelfile, read_only=True)
mysheet = myworkbook['Sheet1']
Write a script that matches the names strings of the staff, auditor, and client columns with StaffNameChart.name_variation, and replace it with StaffNameChart.Staff.name.
Part B: If the client or staff columns are blank, or contain strings not found in the name charts, all of those rows get saved in a new excel document. Edit: I suppose I could also create a new model class called IncompleteAuditReport that just have fields that match up with each column and store it there, then if someone adds a new NameChart variation, it could trigger a quick look-up to see if that could allow this process to complete and the record to be properly added?)
Check the columns in mysheet that will be replaced by foreign keys for the Provider and StudentsApplication tabes. If their respective data doesn't yet exist in their respective tables, add the new record. Either way, then replace their columns with the foreign key that points to the resulting record.
Is this the correct order of operations? Any advice on what specific tools to use from openpyxl etc. to manipulate the data in the most efficient ways, so I can use the fewest resources possible to look-up and then change several hundred thousand fields?
Thank you so much if you've read this far. I'm currently a bit intimidated by the more complex data types, so it's not crystal clear to me the best way to store the data in memory and to manipulate it while it's there.

Simple Django Model (Add to Cart)

This is my first Django project and I am trying to implement add-to-cart features.
What changes should I make in this model so that multiple "Item" can be added into "Order", and also keep track of item quantity?
from django.db import models
from django.utils import timezone
# Create your models here.
class Order(models.Model):
customer = models.ForeignKey('Customer')
ordered_item = models.ForeignKey('OrderQuantity', on_delete=models.CASCADE, null=True)
address = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
class Customer(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
phone = models.CharField(max_length=50)
def __str__(self):
return self.first_name
class Item(models.Model):
name = models.CharField(max_length=50)
price = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
description = models.TextField(null=True)
summary = models.TextField(null=True)
type = models.CharField(max_length=50, null=True)
brand = models.CharField(max_length=50, null=True)
weight = models.DecimalField(default=0.00, max_digits=100, decimal_places=3)
picture = models.ImageField(null=True, upload_to='images/')
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
class OrderQuantity(models.Model):
product = models.ForeignKey('Item')
quantity = models.PositiveIntegerField()
You need to create ManyToManyField in Order Model
class Order(models.Model):
customer = models.ForeignKey('Customer')
ordered_item = models.ForeignKey('OrderQuantity', on_delete=models.CASCADE, null=True)
address = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
items = models.ManyToManyField(Item)
Then you can add items to order in this way:
someorder.items.add(someItem)
Use ManyToManyField in your Item Model
class Item(models.Model):
orders = models.ManyToManyField(Order)
---
So one item have many orders. You can access it by order.item_set or item.orders
It depends on what your Item model is.
If Item is contains a type of product - you may want to use many-to-many field in your Order model, like so:
class Order(models.Model):
...
items = models.ManyToManyField(Item)
...
If Item describes one real item (not type of items), the proper way would be using ForeignKey in your Item model:
class Item(models.Model):
...
order = models.ForeignKey(Order)
...

django queryset - need advice on queryset in view - filters and setting relationships

I am trying to generate a template/report that lists all of the listings (ads) for a customer. Most everything relates to the ID of the Listings table. A customer can have many listings, a listing will only have one listing type, and a listing can have many images. I know my view.py is messed up -- ideally I'd like to send a minimal amount of data to the template. So I would like to only send listings, images and listingtype (1, 2, or 3) data that relates to listings for a specific customer. I'm struggling with the queryset, and building the context. I'm sure I have to add more objects to the context than are currently listed.
I'm am presuming once I get the data to the template I will have to build a table row by row, and do some if/then stuff in the template to deal with the different listingtypes. Let me know if you know of an easier way.
Models.py
class Customer(models.Model):
name = models.CharField(max_length=20, blank=True)
email = models.CharField(max_length=50, blank=True)
user = models.ForeignKey(User, unique=True)
def __unicode__(self):
return unicode(self.user)
class ListingType(models.Model):
desc = models.CharField(max_length=35, blank=True)
def __unicode__(self):
return self.desc
class Listings(models.Model):
createdate = models.DateTimeField(auto_now_add=True)
price = models.IntegerField(null=True, blank=True)
listing_type = models.ForeignKey(ListingType)
customer = models.ForeignKey(Customer)
class Listingtype1(models.Model):
manufacturer = models.CharField(max_length=35, blank=True)
mfg_no = models.CharField(max_length=35, blank=True)
typespecific1 = models.CharField(max_length=35, blank=True)
typespecific2 = models.CharField(max_length=35, blank=True)
listings = models.ForeignKey(Listings)
class Listingtype2(models.Model):
manufacturer = models.CharField(max_length=35, blank=True)
mfg_no = models.CharField(max_length=35, blank=True)
typespecific1 = models.CharField(max_length=35, blank=True)
typespecific2 = models.CharField(max_length=35, blank=True)
listings = models.ForeignKey(Listings)
class Listingtype3(models.Model):
manufacturer = models.CharField(max_length=35, blank=True)
mfg_no = models.CharField(max_length=35, blank=True)
typespecific1 = models.CharField(max_length=35, blank=True)
typespecific2 = models.CharField(max_length=35, blank=True)
listings = models.ForeignKey(Listings)
class Image(models.Model):
title = models.CharField(max_length=60, blank=True, null=True)
image = models.ImageField(upload_to="images/", blank=True, null=True)
thumbnail = models.ImageField(upload_to="images/", blank=True, null=True)
listings = models.ForeignKey(Listings)
Views.py (work in progress)
def listings_customer(request, user_id):
customer = get_object_or_404(Customer, user=user_id)
cusnum=customer.id
listings = Listings.objects.filter(customer=cusnum)
image = Image.objects.all()
context=Context({
'title': 'Listings',
'customer': customer,
'listings' : listings,
'image' : image,
})
return render_to_response('bsmain/listings.html', context)
Take a look on lookups with relations and backwards relationship so you can link all your models in chains like:
Image.objects.filter(listings__customer=customer)
Also, few offtopic advices.
a listing will only have one listing type
So you should use OneToOneField here
You don't need to retrieve customer.id, use customer for lookup.
Use non-plural names for your models (Listings should be Listing) and avoid duplicating your code like in ListingType1 and ListingType2, use model inheritance