Hi I am making a backend server in Django for storing user data from an app.
Below are my models.
class Subscriber(models.Model):
subId = models.IntegerField(max_length=20,unique=True,blank=False)
Name = models.CharField(max_length=25,blank=True)
class SMS(models.Model):
subscriberId = models.ForeignKey(Subscriber, null=False)
epochTime = models.IntegerField(null = False)
time = models.CharField(max_length= 250 ,blank = False)
class Call(models.Model):
subscriberId = models.ForeignKey(Subscriber, null=True)
epochTime = models.IntegerField(null = False)
time = models.CharField(max_length= 50 ,blank = False)
Date = models.CharField(max_length= 50 ,blank = False)
I need to write a Django query which I will give subscriberId and Django will return me to use the data for that user from Call and SMS (basically wants to use Join ).
earlier I have applied this in mysql.
select * from Server_Text JOIN (Server_Call) ON (Server_SMS.subscriberId_id = 11 and Server_Call.subscriberId_id = 11) ;
where Server is my mysql Database.
You shouldn't think in terms of joins and sql queries when you're using Django; the point is that the model layer abstracts these away. You just want to get the Subscriber, then follow the relationships to get the SMS and Call info:
subscriber = Subscriber.objects.get(subId=my_subscriber_id)
print subscriber.sms_set.all() # all SMSs for that subscriber
print subscriber.call_set.all() # all Calls for that subscriber
If you're doing this a lot, you can make it a bit more efficient by using prefetch_related('sms', 'call') in the initial query.
Related
Currently have this code for one of the subscriptions that I have available on my site. The code checks to see if the user has a plan already, if they don't, the else statement is run (works fine) and if they do, the code for updating their current subscription is replaced with the new subscription.(not working)
#login_required
def charge(request):
user_info = request.user.profile
email = user_info.inbox
if request.method == 'POST':
#returns card token in terminal
print('Data:', request.POST)
user_plan = request.user.profile.current_plan
if user_plan != 'None':
'''if they have a plan already, override that plan
with this new plan this is using an already created
user'''
#this throws an error right now
new_plan = stripe.Subscription.modify(
#the current plan(wanting to change)
user_info.subscription_id,
cancel_at_period_end=True,
proration_behavior='create_prorations',
#the new subscription
items=[{'plan':'price_HHU1Y81pU1wrNp',}]
)
user_info.subscription_id = new_plan.id
#if they don't have a subscription already
else:
amount = 10
customer = stripe.Customer.create(
email=email,
source=request.POST['stripeToken'],
description=user_info.genre_one,
)
charge = stripe.Subscription.create(
customer=customer.id,#email of logged in person
items = [{"plan": "price_HHU1Y81pU1wrNp"}],#change plan id depending on plan chosen
)
#updates users current plan with its id and other info
user_info.subscription_id = charge.id
user_info.customer_id = customer.id
user_info.current_plan = 'B'
user_info.save()
return redirect(reverse('success', args=[amount]))
When I try and update the users subscription to the new one I get this runtime error:
Request req_kK2v51jnhuuKsW: Cannot add multiple subscription items with the same plan: price_HHU1Y81pU1wrNp
The Account that I am testing with has a plan that is different than the one that im trying to update to. (this code is for basic plan, the account has the standard plan enabled).
All help is greatly appreciated!
Edit: This is the model data, I tried changing all the 'None' values to something else to see if it would change the error but it didn't.
SUB_PLANS = [
('None','None'),
('B','Basic Plan'),
('S', 'Standard Plan'),
('P', 'Premium Plan'),
]
GENRE_CHOICES = [
('1','None'),
('2','Adventure'),
('3','Action'),
('4','Puzzle'),
('5','Story Based'),
]
# Create your models here.
class Profile(models.Model):
User = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
username = models.CharField(max_length=30)
#where games are sent
inbox = models.EmailField(max_length = 50)
current_plan = models.CharField(max_length = 4, choices = SUB_PLANS, default='None')
#genres they like
genre_one = models.CharField(max_length = 20, choices = GENRE_CHOICES, default = 'None')
genre_two = models.CharField(max_length = 20, choices = GENRE_CHOICES, default = 'None')
genre_three = models.CharField(max_length = 20, choices = GENRE_CHOICES, default = 'None')
subscription_id = models.CharField(max_length = 40, default="None")
customer_id = models.CharField(max_length = 40, default = "None")
'''on account creation plan == null, then once they buy one,
plan is added as a dropdown that they can edit easy'''
def __str__(self):
return self.username
The trick here is that if you're updating an existing Subscription that already has a single item, then you'll need to pass the ID for that SubscriptionItem when updating so that the API knows you're not attempting to add a second SubscriptionItem with the same plan.
Based on that error message, it seems the Plan was already updated on that Subscription, but likely not in the way you're expecting. If the Subscription started out on the "standard" plan, then your code above was executed, it likely added the "basic" plan in addition to the existing standard. I bet they are subscribed to both basic and standard now. In order to update as you expect, you'll want to delete the standard SubscriptionItem and add the basic SubscriptionItem which I'll show code for below. Alternatively, you can update the SubscriptionItem directly to swap the plan.
Note that if you have multiple plans per Subscription, this example will need to be modified to find the correct SubscriptionItem ID. Here's one way to do this:
current_subscription = stripe.Subscription.retrieve(user_info.subscription_id)
new_plan = stripe.Subscription.modify(
user_info.subscription_id,
cancel_at_period_end=True,
proration_behavior='create_prorations',
#the new subscription
items=[{
'id': current_subscription['items'].data[0].id, # note if you have more than one Plan per Subscription, you'll need to improve this. This assumes one plan per sub.
'deleted': True,
}, {
'plan': 'price_HHU1Y81pU1wrNp'
}]
)
I want automatically update field status in my model after 14 days.
Here is my model. I want to change status_of_renting to 0 after 15 days from date_of_rental (if date.today() if greater than date_of_return)
class RentCar(models.Model):
NORMAL = 1
PENALTY = 0
STATUS = (
(NORMAL, 'All is fine'),
(PENALTY, 'Penalty for using car')
)
car = models.ForeignKey('Car', on_delete = models.CASCADE, related_name = 'car')
person = models.ForeignKey('Person', on_delete = models.CASCADE, related_name = 'client')
date_of_rental = models.DateField(blank= True, default=timezone.now)
date_of_return = models.DateField(blank= True, default=date.today() + timedelta(days=14))
status_of_renting = models.IntegerField(choices = STATUS, default = 1)
def __str__(self):
return f'{self.rental} - {self.car} / {self.client.fullname}'
I can override def get_queryset() or dispatch in my generics.ListView, but I*m sure it's terrible decision. Is there some better solution to change the status in field status_of_renting.
views.py
class RentCatView(ListView):
model = RentCar
def get_queryset(self):
self.model.objects.filter(Q(status_of_renting = 1)&Q(date_of_return__lte = date.today())).update(status_of_renting=0)
return self.model.objects.all()
Trying to update database in queryset is indeed bad idea - it will execute every time someone try to fetch list of RentCar which will pollute your database with requests.
You need to setup cron job to run your query to update RentCar. Good thing is that you can run it only once a day, since it is only time that status_of_renting should be changed.
You can use one of django app, such as django-cron or django-background-tasks.
For example, this is what you need to do with django-background-tasks:
from background_task import background
from .models import RentCar
#background(schedule=24*60*60)
def update_status_of_renting(user_id):
RentCar.objects.filter(Q(status_of_renting = 1)&Q(date_of_return__lte = date.today())).update(status_of_renting=0)
I am new to programming, I have a doubt I formed the QuerySet with table data i want to know how to apply condition to the formed queryset and get the count.
Code :
final_set = TaskMaster.objects.filter(istaskactive=True)
I want something like
no_of_rebuild_task = final_set..objects.filter(tasktype.id=1).count
model.py
class TaskMaster(models.Model):
sid = models.CharField(max_length=3)
# Remember to change the default value in processor in production
processor = models.ForeignKey(User,null=True,on_delete=models.CASCADE,default=1)
tasktype = models.ForeignKey(TaskTypeTable, null=True,on_delete=models.CASCADE)
task_title = models.TextField(null=True)
task_description = models.TextField(null=True)
datacenter = models.ForeignKey(DatacenterTable,null=True,on_delete=models.CASCADE)
priority = models.ForeignKey(PriorityTable, null=True,on_delete=models.CASCADE)
status = models.ForeignKey(StatusTable, default=1,on_delete=models.CASCADE)
pid = models.IntegerField(null=True)
sourceincident = models.CharField(max_length=250,null=True)
errorincident = models.CharField(max_length=250,null=True)
processingteam =
models.ForeignKey(TeamTable,null=True,on_delete=models.CASCADE)
createddate = models.DateField(("Date"), default=datetime.date.today)
duedate = models.DateField(("Date"), default=datetime.date.today)
istaskactive = models.BooleanField(default=True)
In Django ORM you can use count() to count the number of records in the selected table.
So for your query it can be
no_of_rebuild_task = TaskMaster.objects.filter(istaskactive=True, tasktype_id=1).count()
See effective way of Django ORM
and count() here.
no_of_rebuild_task = final_set.filter(tasktype__id=1).count()
I am using postgresql_psycopg2 database in one of my django powered website.Previously i have used sqlite3 in test basis,but i have left it because now i am going to live my project in server,so we know that in sqlite3 if we edit model,then we have to delete the whole database,cause as far as i know ,sqlite3 don't provide any database update service or migration service.
So i have switched in to the postgresql_psycopg2.As i am new in django,now how can i kept my previous data after updating model.
for example i have a
Photo model something like this,
class Photo(models.Model):
name = models.CharField(max_length = 100)
photo = models.ImageField(upload_to = 'photos', blank=False,null=True)
approved = models.BooleanField(default = False)
approved_time = models.DateTimeField(auto_now=True,null=True,blank=True)
uploaded_time = models.DateTimeField()
description = models.CharField(max_length = 500 , blank = False , null = True)
keyword = models.CharField(max_length = 500 , blank = False , null = True)
user = models.ForeignKey(User)
now i want to add a extra field in my Photo model,
class Photo(models.Model):
name = models.CharField(max_length = 100)
photo = models.ImageField(upload_to = 'photos', blank=False,null=True)
approved = models.BooleanField(default = False)
approved_time = models.DateTimeField(auto_now=True,null=True,blank=True)
uploaded_time = models.DateTimeField()
description = models.CharField(max_length = 500 , blank = False , null = True)
keyword = models.CharField(max_length = 500 , blank = False , null = True)
user = models.ForeignKey(User)
#new field added
photo_dpi = models.CharField(max_length = 500 , blank = False , null = True)
now how can i kept my previous data after adding a new field.
You should use migrations to edit database structure:
https://docs.djangoproject.com/en/1.7/topics/migrations/
Or, if your django version is less than 1.7, South package:
http://south.readthedocs.org/en/latest/
Just run makemigrations and migrate commands:
python manage.py makemigrations
python manage.py migrate
UPDATE: makemigrations/migrate commands are available since django 1.7.
As #eugene-soldatov mentioned in his answer for django 1.5 you can use the South app.
Another option is to alter the table manually by executing the following SQL query:
echo "ALTER TABLE myapp_photo ADD COLUMN photo_dpi VARCHAR(500) NULL;" | python manage.py dbshell
Where myapp is the name of your application.
I have two simple models in my Django app. Here's what they look like:
class Host(models.Model):
url = models.URLField(max_length= 200)
ssl = models.BooleanField(default = False)
class Query(models.Model):
host = models.ForeignKey(Host)
date = models.DateTimeField(auto_now_add = True)
latency = models.FloatField(null = True)
success = models.BooleanField(default = False)
error = models.CharField(max_length= 2000, null = True)
When i access the Host model, I only have access to the two fields url and ssl. When querying the Host model, I would like three extra fields to computed and returned dyanmicaly. These are the average_latency which would be the average of the not-null latency field of all the child Query records so i can access it something like this:
t = Tracker.objects.get(id = 1)
t.url
t.average_latency
Could someone please explain how I can do this or point me to some examples/documentation?
Thank you.
You can just use class properties:
class Host(models.Model):
.
.
.
#property
def average_latency(self):
# calculate latency from Query model ...
return latency
Bear in mind that this is a read-only property.
You can check django-denorm, it's pretty much about what you're trying to achievie. I also have some flashbacks that there are other similar django apps.