Django 4.0. Updating field once every day - python

I have a Book model that has a integer field count which is the number of users that have this book in their readlist. Users can add a book to their ReadList model (many to many field). I want to update the count in the book model once a day...how should I go about doing this?
Will be using this to displaying trending books and book rank based on user count.
Book Model:
class Book(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.TextField()
user_count = models.IntegerField()
pages = models.IntegerField()
genres = models.ManyToManyField(Genre)
def __str__(self):
return self.name
ReadList Model:
class ReadList(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
readlist = models.ManyToManyField(Book, related_name='readlist', blank=True)
def __str__(self):
return self.user.username

Django unfortunately doesn't do scheduling very well. You can actually generate this information already, via the related_name, with the advantage this will be realtime!
Let's start with a queryset for all books. Imagine you put this in one of your views.
books = Book.objects.all()
Now you have all your books, but no data on booklist numbers. So we can annotate that information via the query
from django.db.models import Count
books = Book.objects.all().annotate(user_count = Count('readlist')
Useful, but in no particular order, lets arrange it from highest to lowest.
books = Book.objects.all().annotate(user_count = Count('readlist') .order_by('-user_count')
But do we want it for every book in the store? Let's limit to the top 10.
books = Book.objects.all().annotate(user_count = Count('readlist') .order_by('-user_count')[:10]
The books don't necessarily know their own place in the heirarchy, though. Lets cycle through them and give them another impromptu field (Querysets aren't really indexed, so we can do this ourselves)
for index, book in enumerate(books):
book.placing = index
Pass context['books'] = books to your template and you should be able to do the following:
{% for book in books %}
Title:{{book.title}} <br>
Position:{{book.placing}} <br>
In :{{book.user_lists}} reading lists<br>
And there you have it, an up to the minute list of the top 10 books sorted by user_count without having to use external scheduling. Make sure you add the palcing last, as any further DB queries on the queryset will cause the query to be remade.

Related

How can I fix my Django model to store multiple lists of strings inputted by the user. Which can then be retrieved in the future as an object?

I'm trying to make this simple app that retrieves a list of string(s) entered by the user, which is then stored in an object. The idea is for users to create a list of movies for each of their favorite genres. A "user-created-dictionary" sort of speak...
Like so in Python:
UserMovies = {
Scary : ['A','B','C'],
Funny : ['D'],
Sad : ['E','F],
Thriller : ['G','H','I','J']
}
Using the example above, the ideal Model.py would store user created dictionary keys, followed by storing values for keys, in a list.
I'm trying to replicate the same in my Django model, but I'm not sure how to create a many-to-many relationship that stores data in a list.
EDIT: I have made new corrections, here is the most recent model.
class UserGenres(models.Model):
username = models.ForeignKey(UserModel.username)
genre = models.ManyToManyField(models.CharField(max_length=1000))
def __str__(self):
return self.genre
class TotalGenre(models.Model):
username = models.ForeignKey(UserGenres.user)
total_Genre = models.IntegerField(blank=True, null=True)
def total_genre(self):
self.total_genre = UserGenre.objects.aggregate(Sum('genre', distinct=True))
self.save()
class Movies(models.Model):
owner = models.ManyToManyField(UserGenre.user)
genre = models.ManyToManyField(UserGenre.genre)
movies = ArrayField(models.CharField(choices=MOVIES))
number_of_movies = models.IntegerField(blank=True, null=True)
def total_movies(self):
self.number_of_movies = Movies.objects.aggregate(Sum('number_of_movies ', distinct=True))
self.save()
def __str__(self):
return self.movies
What I'm striving for is being able to store the genres for each user, including the movies within the genres. All of this being a CRUD app. Given the info, what would be the best way to structure the model? currently struggling with this one.
It will be something like this, read
#https://docs.djangoproject.com/en/3.1/ref/models/fields/#manytomanyfield
class Genre(models.Model):
title = models.TextChoices(max_length=1000, choices=IMDBmoviesTuple)
class UserGenres(models.Model):
user = models.ForeignKey(UserModel.username)
genres = models.ManyToManyField(max_length=1000) #this will be array
class Movie(models.Model):
#movie name etc
genre = models.ManyToManyField(max_length=1000) #many to many, one movie can be of many genres

How to reduce quantity of an item in main table when it is being used in another table - django

I am creating my model in Django and I have a many to many relationship between supplies and van kits. The idea is that an "item" can belong to many "van kits" and a "van kit" can have many " items. I created an intermediary model that will hold the relationship, but I am struggling to figure out a way to relate the quantity in the van kit table to the quantity in the main supplies table. For example, if I wanted to mark an item in the van kit as damaged and reduce the quantity of that supply in the van kit, I would also want to reduce the total count of that supply in the main "supplies" table until it has been replenished. I am thinking that maybe I'll have to create a function in my views file to carry out that logic, but I wanted to know if it could be implemented in my model design instead to minimize chances of error. Here's my code:
class supplies(models.Model):
class Meta:
verbose_name_plural = "supplies"
# limit the user to selecting a pre-set category
choices = (
('CREW-GEAR','CREW-GEAR'),
('CONSUMABLE','CONSUMABLE'),
('BACK-COUNTRY','BACK-COUNTRY')
)
supplyName = models.CharField(max_length=30, blank=False) # if they go over the max length, we'll get a 500 error
category = models.CharField(max_length=20, choices = choices, blank=False)
quantity = models.PositiveSmallIntegerField(blank=False) # set up default
price = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) # inputting price is optional
def __str__(self):
return self.supplyName
class van_kit(models.Model):
supply_name = models.ManyToManyField(supplies, through='KitSupplies',through_fields=('vanKit','supplyName'), related_name="supplies")
van_kit_name = models.CharField(max_length=100)
vanName = models.ForeignKey(vans, on_delete=models.CASCADE)
def __str__(self):
return self.van_kit_name
class KitSupplies(models.Model):
supplyName = models.ForeignKey(supplies, on_delete=models.CASCADE)
vanKit = models.ForeignKey(van_kit, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(blank=False)
def __str__(self):
return str(self.supplyName)
class Meta:
verbose_name_plural = 'Kit Supplies'
I am fairly new to django, I have to learn it for a class project so if my logic is flawed or if a better way to do it is obvious, please respectfully let me know. I'm open to new ways of doing it. Also, I've read through the documentation on using "through" and "through_fields" to work with the junction table, but I'm worried I may not be using it correctly. Thanks in advance.
One option would be to drop/remove the field quantity from your supplies model and just use a query to get the total quantity.
This would be a bit more expensive, as the query would need to be run each time you want to know the number, but on the other hand it simplifies your design as you don't need any update logic for the field supplies.quantity.
The query could look as simple as this:
>>> from django.db.models import Sum
>>> supplies_instance.kitsupplies_set.aggregate(Sum('quantity'))
{'quantity__sum': 1234}
You could even make it a property on the model for easy access:
class supplies(models.Model):
...
#property
def quantity(self):
data = self.kitsupplies_set.aggregate(Sum('quantity'))
return data['quantity__sum']

Displaying "info" by selecting foreign key in django admin

I was introduced to Python and Django about two weeks ago, so bear with me. I should also say now that I am using Django 1.6 and Python 3.3.
My project is an order management system. Here's how it works: A customer comes into a store and orders an item. That item is put in an order, which is idle until the employee places the order with a supplier. Basically, I have an Order table, which collects information like customer_name, order_date, status, etc. Then I have an EmployeeOrder table (1-1 relationship with Order) which has all of the elements of an Order, but also takes in employee_placed and employee_order_date (pretty much just extends Order).
What I'm trying to do is write code so that when the user selects which customer Order is being fulfilled by placing an EmployeeOrder, that customer Order's information is displayed. I don't really care how it is displayed right now, a pop up will work just fine. I just don't know how to do it and I haven't come across it anywhere. Right now the drop down box just displays Order 1, Order 2, etc. The user isn't going to remember which items were included in which order, so that's why I want the order information to be shown. Anyway, here's my code so far:
models.py
class Order(models.Model):
customer_order_date = models.DateTimeField('Date helped')
customer_placed = models.ForeignKey(Customer)
employee_helped = models.ForeignKey(Employee)
STATUS_OF_ORDER = (
('IDLE', 'Not yet ordered'),
('SHIP', 'Awaiting delivery'),
('PICK', 'Ready for pickup'),
('UNAV', 'Unavailable for order'),
('BACK', 'Backordered - awaiting delivery'),
('CANC', 'Canceled by customer'),
('ARCH', 'Fulfilled - archived'),
)
status = models.CharField(max_length=4, choices=STATUS_OF_ORDER,
default='IDLE', editable=False)
paid = models.BooleanField('Paid', default=False)
ship = models.BooleanField('Ship', default=False)
comments = models.CharField(max_length=200, blank=True, null=True)
item = models.ManyToManyField(Item)
def __str__(self):
return 'Order ' + str(self.id)
def is_idle(self):
return self.status == 'IDLE'
class EmployeeOrder(models.Model):
order = models.OneToOneField(Order, primary_key=True,
limit_choices_to={'status': 'IDLE'})
employee_order_date = models.DateTimeField('Date ordered')
employee_placed = models.ForeignKey(Employee)
admin.py
class OrderAdmin(admin.ModelAdmin):
list_display = ('customer_order_date', 'customer_placed')
raw_id_fields = ('customer_placed', 'item')
class EmployeeOrderAdmin(admin.ModelAdmin):
list_display = ('employee_order_date', 'employee_placed')
Any and all help is appreciated as I still admit that I am a total noob when it comes to Python and Django!
It sounds to me like you want an employee to be able to use the admin site to create an employee order from a customer order. I think it could be as simple as adding a raw ID field for the customer order. That is, I think you can just change EmployeeOrderAdmin like so:
class EmployeeOrderAdmin(admin.ModelAdmin):
list_display = ('employee_order_date', 'employee_placed')
raw_id_fields = ('order',)
Now when an employee creates an employee order, they will be able to use the OrderAdmin page to find the order they want.
Additionally, suppose you want that pop-up window to display the orders in a particular way. In that case, keep in mind that requests to display that pop-up window will contain an additional GET parameter called pop. You could:
class OrderAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(ActiveOfferAdmin, self).queryset(request)
if request.GET.get('pop'):
return qs.order_by(...)
return qs

Django one-to-many relations in a template

I am searching of a method to obtain html forms from some one-to-many relations, like order-lineorder, invoice-lineinvoice, etc.
Let me an example:
# models.py
class Order(models.Model):
date = models.DateTimeField()
number = models.IntegerField(default=0)
class LineOrder(models.Model):
description = models.TextField()
price = models.FloatField()
order = models.ForeignKey(Order)
# views.py
def order_form(request):
form = OrderForm()
table_lineorder = LineOrderTable([])
RequestConfig(request).configure(table)
return render(request, "order_form.html", {"form": form, "table": table_lineorder})
Then, I want to obtain the order template with "generic attributes" (date, number), and a table list (originally empty) of lines order. Add some action like add, edit and remove must be possible.
I think that a solution like django-tables2 is possible, but I can't add rows dinamically, I think.
Thanks in advice.
[EDIT]
I have found the solution. It is django-dynamic-formset
I'm not quite clear about your question, but I guess this might be what you want:
class Order(models.Model):
date = models.DateTimeField()
number = models.IntegerField(default=0)
items = model.ManyToManyField(Item)
class Item(models.Model):
description = models.TextField()
price = models.FloatField()
It should be equivalent to one-to-many if you don't assign one Item to multiple Orders.

Django retrieve all related attributes for model

I am writing a store based app. Say theres Store A , Store A can have multiple users, and each user can belong to multiple stores. However, each store has Products and each Product has sizes associated with them.
class Variation(models.Model):
product = models.ForeignKey("Product")
size = models.CharField(choices=SIZES, max_length=5)
pid = models.CharField(unique=True, max_length=100, verbose_name="Product ID")
id_type = models.CharField(max_length=5, choices=ID_TYPES, default="UPC")
price = models.DecimalField(max_digits=5, decimal_places=2)
store = models.ForeignKey("Store")
class Meta:
unique_together = ("store", "pid")
class Product(models.Model):
item = models.CharField(max_length=100, verbose_name="Parent SKU", help_text="reference# - Color Code")
# Google docs sp key
store = models.ForeignKey(Store)
class Store(models.Model):
name = models.CharField(max_length=100)
store_id = models.PositiveIntegerField(unique=True)
admins = models.ManyToManyField(User)
objects = StoreManager()
def __unicode__(self):
return self.name
so i had to write a custom manager for Product in order to filter all products by store, and override the queryset method for this model's admin class, and do so for EVERY attribute belonging to said store. So basically my question is, is there a way to filter all attributes related to a store per store, ex products, tickets, variations
EDIT
This is the product manager so far
class ProductManager(models.Manager):
def active(self, **kwargs):
return self.filter(in_queue=False, **kwargs)
def by_store(self, store=None, **kwargs):
return self.filter(store__id__exact=store, **kwargs)
def from_user(self, request):
qs = self.model.objects.none()
for store in request.user.store_set.all():
qs = qs | store.product_set.filter(in_queue=False)
return qs
so basically, in order to display the products in the change list page, i use the from user method, which returns all the products available to the logged in user
it sounds like what you want to be using is the the django "Sites" framework
add a ForeignKey to Store to point to Site and make it unique.
it may be wise to point Variation and Products' ForeignKeys at Site instead of Store at this point too so that in your views you can filter your results by current site.

Categories

Resources