django database structure for a gym members workout management - python

i would like to develop a django management app for a small gym.
we have a list of members
each member could have 1 or more card
each card could have 1 or more workout
each workout could have 1 or more exercise
each exercise has the following fields:
exercise name (can be choose from a list of exercise names),
series number (can be choose from a list of series),
repetition number (can be choose from a list of repetition),
execution mode (can be choose from a list of executions),
rest time (can be choose from a list of executions).
Here is my possibile implementation of models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Member(models.Model):
#Member data
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
#Contact
email = models.EmailField(blank=True, null=True)
phone = models.CharField(max_length=50, blank=True, null=True)
#Body
birthday = models.DateField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
weigth = models.IntegerField(blank=True, null=True)
#Trainer notes
trainer = models.ForeignKey(User, limit_choices_to={'is_staff': True, 'is_superuser': False}, blank=True, null=True)
note = models.CharField(max_length=160, blank=True, null=True)
#Registration status
registration = models.DateField(auto_now_add=True)
expiration = models.DateField(blank=True, null=True)
card = models.OneToOneField('Card')
def __str__(self):
return u'%s %s' % (self.surname, self.name)
class Card(models.Model):
number = models.IntegerField()
#Card status
card_creation = models.DateField(auto_now_add=True)
card_expiration = models.DateField(blank=True, null=True)
workout = models.ForeignKey('Workout')
def __str__(self):
return u'%s' % (self.number)
class Workout(models.Model):
number = models.IntegerField()
exercise = models.ForeignKey('Exercise')
def __str__(self):
return u'%s' % (self.number)
class Exercise(models.Model):
name = models.ForeignKey('Name')
series = models.ForeignKey('Serie')
repetitions = models.ForeignKey('Repetition')
executions = models.ForeignKey('Execution', blank=True, null=True)
rest = models.ForeignKey('Rest')
def __str__(self):
return u'%s' % (self.name)
class Name(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.name)
class Serie(models.Model):
serie = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.serie)
class Repetition(models.Model):
repetition = models.IntegerField()
def __str__(self):
return u'%s' % (self.repetition)
class Execution(models.Model):
execution = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.execution)
class Rest(models.Model):
rest = models.IntegerField()
def __str__(self):
return u'%s' % (self.rest)
I'm not sure if this works as described. Could you please suggest a possible implementation?
At the end I would like to have only one view with all data: member, card, workout... so the staff user can modify the user and the linked workout card) is it possible with admin.py or do I need a custom admin?

That looks pretty good, and like Samidh T said in the comments you should open up a dev server with sqlite and play around with it. See what's working what's not. That's the best thing you could do.
However, since you asked, here are a couple notes to bear in mind:
"each member could have 1 or more card" - Then why is you card field in Memeber a OneToOne? Wouldn't it make more sense to do a ForeignKey (essentially a ManyToOne) field for Card linking it to member?
"each card could have 1 or more workout" - If you have a ForeignKey from card to workout, then you are actually doing the opposite of what you described, you're doing a Many (cards) for One (workout). But maybe this is what you want? Or maybe you actually want it to be a ManyToManyField? Because each workout probably has different cards and vice-versa. I really can't tell what's the best fit here, but it's something you might want to think over.
"each workout could have 1 or more exercise" Same as with the point before.
I see that every field in your exercise is a ForeingKey. Now again - this is isn't a bad choice or idea, but you should consider what this entails, and consider replacing it with a ManyToMany or, if one of the fields is a static list (i.e. you have a limited list of available names that you know won't change in the future drastically) then you can use a CharField with option choices=.
I can't exactly tell you "this is bad", "this is good", it is a very project-subjective thing, but I hope my few tips helped you in some way. In the end, it all boils down to what you need. If you find yourself confused, I suggest reading a little about table relationships in SQL and how they work.
Django is fantastic for realizing complex relationships, but using it without learning a little bit SQL before can be confusing sometimes because you only see the end result and hardly ever look at the tables themselves.

Related

how to copy data from model to another model in Django after filtering?

here is the models:
class Rooms(models.Model):
name=models.CharField(max_length=100)
image=models.URLField()
max_person=models.CharField(max_length=100)
office=models.CharField(max_length=200)
status=models.CharField(max_length=200)
cost=models.CharField(null=True,max_length=250)
roomId=models.CharField(max_length=100,null=True)
Address= models.CharField(max_length=100,null=True)
def __str__(self):
return str(self.name)
class Available_Rooms(models.Model):
users=models.ForeignKey(Rooms,on_delete=models.CASCADE)
name=models.CharField(max_length=100)
image=models.URLField()
max_person=models.CharField(max_length=100)
office=models.CharField(max_length=200)
status=models.CharField(max_length=200)
cost=models.CharField(null=True,max_length=250)
roomId=models.CharField(max_length=100,null=True)
Address= models.CharField(max_length=100,null=True)
def __str__(self):
return str(self.name)
at model "rooms" there is 100 objects (rooms)
and what I want filter it and list rooms that have maxperson = 4
availablity= Rooms.objects.filter(maxperson="4").all()
and want to to copy the rooms details to the other model "Available_Rooms"
any idea how that can be done?
many thanks in advance
and want to to copy the rooms details to the other model Available_Rooms.
Please don't: it makes no sense to do that: you are introducing data duplication, which is an antipattern. This means that if you now want to change for example the name of a Room, you need to modify both the Rooms and the Available_Rooms. This will thus introduce a lot of extra logic to keep the rooms in sync.
What you can for example do is add a BooleanField that determines if the room is available, with:
class Room(models.Model):
name = models.CharField(max_length=100)
image = models.URLField()
max_person = models.IntegerField()
office = models.CharField(max_length=200)
status = models.CharField(max_length=200)
cost = models.IntegerField(null=True)
room_id = models.CharField(max_length=100,null=True)
address = models.CharField(max_length=100)
available = models.BooleanField(default=False)
def __str__(self):
return str(self.name)
Then you can for example make all rooms available that have as max_person=4 with:
Room.objects.filter(max_person=4).update(available=True)
Note: normally a Django model is given a singular name, so Room instead of Rooms.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: room_id instead of roomId.

What is Football game statistics Django Model logic?

I am creating an app that visualizes football game statistics on Django. I take data from https://fbref.com/ as a CSV file. I have a python script that cleans data and create data frame with ['Player', 'Shots', 'SCA', 'Touches', 'Pass', 'Carries', 'Press', 'Tackled', 'Interceptions', 'Blocks'] columns (I can add Team name, Game Date, Home/Away or whatever).
And now I need to create models to store this data. I don't know what models do I need.
Option 1 (only one model):
class GameStats(models.Model):
date = models.DateField()
team_name = models.CharField(max_length=20)
home_away = models.CharField(max_length=20, choices=HOME_AWAY)
name = models.CharField(max_length=20)
number = models.IntegerField()
age = models.IntegerField()
shots = models.IntegerField()
SCA = models.IntegerField()
touches = models.IntegerField()
passes = models.IntegerField()
But it will give one Row of data. Technically, I can group rows by Team_name and Date.
Option 2:
from django.db import models
class Team(models.Model):
name = models.CharField(max_length=200)
league = models.CharField(max_length=200)
def __str__(self):
return self.name
class Player(models.Model):
name = models.CharField(max_length=200)
number = models.IntegerField()
age = models.IntegerField()
team = models.ForeignKey(Team, related_name='team', on_delete=models.CASCADE)
def __str__(self):
return self.name
class HomeTeam(models.Model):
team = models.ForeignKey(Team, related_name='home_team', on_delete=models.CASCADE)
players = models.ManyToManyField(Player)
def __str__(self):
return self.team
class AwayTeam(models.Model):
team = models.ForeignKey(Team, related_name='away_team', on_delete=models.CASCADE)
players = models.ManyToManyField(Player)
def __str__(self):
return self.team
class Game(models.Model):
title = models.CharField(max_length=200)
homeTeam = models.OneToOneField(HomeTeam, on_delete=models.CASCADE)
awayTeam = models.OneToOneField(AwayTeam, on_delete=models.CASCADE)
def __str__(self):
return self.title
In Option 2 I can understand where to put Game statistics and a list of the players.
Would be great if someone could write proper models. I really stack!
There is no one way to do it, so every answer you get for this question is going to be opinionated. That being said, for my personal preference, I would prefer the first modal approach as it is simple and has all the data in one place. I don't see a point of separating the columns into different database tables unless you know these different subset of columns are going to be used in some other models later down the line. Even then, you can always link the whole model with a ForeignKey to the new model and only use the data that you need.
Another reason I prefer the first approach is that the data does not have many columns, so dividing it into many smaller parts is making it complicated for no reason. You will be querying the database more in second approach, and later down the line, it may become difficult to keep track of things. But that is my opinion, so take it with a grain of salt.

Get max value from a set of rows

This question is in relation to project 2 of the cs50 course which can be found here
I have looked at the following documentation:
Django queryset API ref
Django making queries
Plus, I have also taken a look at the aggregate and annotate things.
I've created the table in the template file, which is pretty straight forward I think. The missing column is what I'm trying to fill. Image below
These are the models that I have created
class User(AbstractUser):
pass
class Category(models.Model):
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Listing(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
initial_bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date_created = models.DateField(auto_now=True)
def __str__(self):
return self.title
class Bid(models.Model):
whoDidBid = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
list_item = models.ForeignKey(Listing, default=0, on_delete=models.CASCADE)
bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now=True)
def __str__(self):
return_string = '{0.whoDidBid} {0.list_item} {0.bid}'
return return_string.format(self)
This is the closest I could come to after a very long time. But the result I get is just the number 2. Ref image below
Listing.objects.filter(title='Cabinet').aggregate(Max('bid'))
Where 'Cabinet' is a Listing object that I have created. And placed two bids on them.
So the question is, how do I get the Maximum bid value(i.e. 110 for this case) for a particular listing? Using the orm. I think if I used a raw sql query, I could build a dict, send it to the template with the queryset. Then while looping through the queryset, get the value for the key, where the key is the name of the listing or something along those lines. Nah, I would like to know how to do this through the ORM please.
Here's answer #1
Bid.objects.filter(list_item__title='Cabinet').prefetch_related('list_item').aggregate(Max('bid'))
What happens when you try this (sorry, I don't have any objects like this to test on):
Bid.objects.values(list_item__title).prefetch_related('list_item').annotate(Max('bid'))

Reference individual field of model in another model?

I have three models so far:
class clientCode(models.Model):
unique_id = models.CharField(max_length=9, blank=False)
def __str__(self):
return self.unique_id
class clientAccount(models.Model):
clientCode = models.ForeignKey(ClientCode,
on_delete=models.CASCADE, related_name='clientBusiness',null=True)
clientAccount = models.CharField(max_length=13, blank=False)
clientName = models.CharField(max_length=45, blank=False)
class assets(models.Model):
assetName = models.CharField(max_length=45, blank=False)
assetCurrency = models.CharField(max_length=45, blank=False)
assetCode = models.CharField(max_length=15, blank=False)
def __str__(self):
return self.assetName
Now, I would like to have a model containing ALL the fields from the above + an amount and transaction.
I started as so...
class Holdings(models.Model):
holdingsName = models.ManyToManyField(assets)
The issue is this, while this returns the assetName which is what I'd like, how do I retrieve the assetCurrency?
I guess I need to know: How do I reference an individual field from one model another model?
I am truly lost on how to do this, i've tried various ForeignKey, ManytoMany.. Is the correct approach to build a form that includes all the fields and posts to said model?
To clarify, I would essentially like clientAccount and assets to remain as lists, and the Holdings model fields to be dropdowns relating to these models?
Sorry if this is unclear and thanks in advance for any help! - I'm sure Ive got the wrong end of the stick on how to build the models.
Ok you need to first of all determine how are your models related to each other or what are the relationships between ClientCode, ClientAccount, Assets and Holdings.
As an example, loosely defined holdings are stocks, property or other finanical assets in someone's possesion. So your models for holdings and assets could be something like that.
Also please follow the Django Naming Conventions for your code. I have changed field/model names to reflect that below. Link here
class Asset(models.Model)
asset_name = models.CharField(max_length=45, blank=False)
asset_currency = models.CharField(max_length=45, blank=False)
asset_code = models.CharField(max_length=15, blank=False)
def __str__(self):
return self.asset_name
class Holding(models.Model)
holding_name = models.CharField(max_length=50)
assets = models.ManyToManyField(Asset, related_name='holdings',
through='HoldingAsset')# if you want some more explicit fields on the through model
def __str__(self):
assets = self.assets.all()
asset_currencies = [asset.asset_currency for asset in assets]
return '%s -- %s' % (self.holding_name, self.asset_currencies)
Now if you get a holding object like this (ignoring any unhandled errors here)
holding = models.Holding.objects.get(holding_name='Test_Holdings')
to access your assets and their currencies , you could do something like this.
assets = holding.assets.all()
asset_currencies = [asset.asset_currency for asset in assets]
To load holdings based on assets, or vice-versa, you will need to use modelforms and use a chained drop-down approach.

Tricky Django QuerySet with Complicated ForeignKey Traversals

I am adapting Jim McGaw's e-commerce site from Beginning Django E-Commerce for my client's use. My client sells builds of computers composed of a custom set of parts. The parts that go into a system will change. For instance, the Super Samurai system sold two years from now will have different parts than the one we sell tomorrow. So as we sell each Super Samurai system we need a snapshot of what parts went into the Super Samurai at the moment in time of the sale.
I am having a problem with the QuerySet that copies all of the parts from the table that maps parts to builds (i.e. the parts that go into the Super Samurai)...
class Build(models.Model):
build = models.ForeignKey(PartModel, related_name='+')
part = models.ForeignKey(PartModel, related_name='+')
quantity = models.PositiveSmallIntegerField(default=1)
class Meta:
abstract = True
unique_together = ('build', 'part')
def __unicode__(self):
return self.build.name + ' with ' + str(self.quantity) + ' * ' + \
self.part.family.make.name + ' ' + self.part.name
class BuildPart(Build):
pass
class Meta:
verbose_name = "Build Part"
I need to copy the build parts from the BuildPart table into the OrderBuildPart table...
class OrderBuildPart(Build):
orderItem = models.ForeignKey(OrderItem, unique=False)
class Meta:
verbose_name = "Ordered Build Part"
...so that in the future we know which parts went into so-and-so's build.
McGaw's e-commrece site doesn't allow for items to be bundles of other items. So rather than create some nightmarish scenario of two different tables (and two series of SKUs) for builds and their parts, I wanted a build to be just like any other part...
class PartModel(models.Model):
family = models.ForeignKey(PartFamily)
name = models.CharField("Model Name", max_length=50, unique=True)
slug = models.SlugField(help_text="http://www.Knowele.com/<b>*slug*</b>",
unique=True)
vpn = models.CharField("VPN", help_text="Vendor's Part Number",
max_length=30, blank=True, null=True)
url = models.URLField("URL", blank=True, null=True)
costurl = models.URLField("Cost URL", blank=True, null=True)
cost = models.DecimalField(help_text="How much knowele.com pays", max_digits=9, decimal_places=2, blank=True, null=True)
price = models.DecimalField(help_text="How much a customer pays", max_digits=9, decimal_places=2, blank=True, null=True)
isActive = models.BooleanField(default=True)
isBestseller = models.BooleanField(default=False)
isFeatured = models.BooleanField(default=False)
isBuild = models.BooleanField(default=False)
description = models.TextField(blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
buildpart = models.ManyToManyField('self', through='BuildPart',
symmetrical=False, related_name='+')
class Meta:
ordering = ['name']
verbose_name = "Product Model"
def __unicode__(self):
return self.name
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('productdetail', args=[self.slug])
The buildpart field references the ManyToMany BuildPart table which allows a build to have many parts and for a part to be associated with many builds.
Through adapting McGaw's code I get pretty much what I need until I finalize the PayPal payment and try to record what parts went into the sold builds at the precise moment of sale...
def payment(request):
token = request.POST['token']
payer = request.POST['payer']
result = paypal.do_express_checkout_payment(request, token, payer)
if result['ACK'][0] in ['Success', 'SuccessWithWarning']:
cart = Cart.objects.get(cart_id=get_cart_id(request))
finalOrder = Order()
finalOrder.cart_id = get_cart_id(request)
finalOrder.token = token
finalOrder.corID = result['CORRELATIONID'][0]
finalOrder.payerID = payer
finalOrder.ipAddress = request.META['REMOTE_ADDR']
finalOrder.first = cart.first
finalOrder.last = cart.last
finalOrder.address = cart.address
finalOrder.email = cart.email
finalOrder.transactionID = result['PAYMENTINFO_0_TRANSACTIONID'][0]
finalOrder.status = 'f'
finalOrder.save()
for item in get_cart_items(request):
oi = OrderItem()
oi.cart_id = item.cart_id
oi.quantity = item.quantity
oi.product = item.product
oi.price = item.price()
oi.save()
if item.product.isBuild:
for part in get_build_parts(request, item):
bp = OrderBuildPart()
bp.build = part.build
bp.part = part.part
bp.quantity = part.quantity
bp.orderItem = oi
bp.save()
empty_cart(request)
return render(request, 'payment.html', locals())
Everything seems fine until we hit the get_build_parts function...
def get_build_parts(request, part):
return BuildPart.objects.filter(build__id=part__product__pk)
...where Django's post-mortem complains "NameError at /payment/ global name 'part__product__pk' is not defined"
How do I traverse these complicated relationships so my boss can look up what parts went into each customer's builds?
The value side of the lookup doesn't work the way you think it does. The double-underscore stuff is for the left-hand side only: in effect, it's a hack to get round Python's syntax requirements. On the right-hand side, you pass a normal expression, which can follow object relationships using the standard dot syntax:
return BuildPart.objects.filter(build__id=part.product.pk)
Try BuildPart.objects.filter(build=part__product) instead of what you have.
Also, it looks like your "post mortem" is coming from the webapp actually being used. You should be learning of problems like this from unit tests failing, not from an HTTP call.

Categories

Resources