Possible to delete an object's specific row in django? - python

I have model that creates several different rows. Like this...
class Myteam(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
QB = models.CharField(max_length=80, null=True)
RB1 = models.CharField(max_length=80, null=True)
WR = models.CharField(max_length=80, null=True)
TE = models.CharField(max_length=80, null=True)
D = models.CharField(max_length=80, null=True)
K = models.CharField(max_length=80, null=True)
In my template, I'm looping through the rows and displaying them as html table rows. I've added a delete function to each row because I'd like the app's user to be able delete a player from their "Myteam" object. Problem is, I can only delete the entire object because there's only one id which is for the entire object. The template looks like this right now. Here's two rows as an example.
<tbody>
{% for t in team %}
<tr>
<td id="" > {{ t.QB }}
Delete
</td>
<tr>
<td> {{ t.RB1 }}
Delete
</td>
</tr>
<tr>
I did come across one possible solution here which suggested using {{ forloop.counter }} to assign individual id's to the row, but I can't get this to work how I would like.
Just in case, here's the views.py
def delete_player(request, id):
player = Myteam.objects.get(id=id)
player.delete()
return redirect('show')
I feel like there's probably a pretty basic solution to this but I'm new to django and am having trouble finding such answers. Any help is greatly appreciated.

Ok, so those model fields are database table columns, not rows. Instances of the model are table rows.
You don't delete columns, instead you set them to null. Your view could for example take the column name as a string argument:
def delete_player(request, id, col_name):
player = Myteam.objects.get(id=id)
setattr(player, col_name, None)
player.save()
return redirect('show')
Also since your fields are CharFields, it's best practice to not make them nullable (meaning, don't set null=True), but instead use an empty string "" to indicate an unset value. This way you don't have two different values that indicate emptyness. Thus in the view you would use setattr(player, col_name, "").

Related

How to select distinct column values from mysql database in django?

I need to retrieve distinct value from query set and display it on a div.
Here is my model.py:
class Persons(models.Model):
id = models.IntegerField(primary_key=True)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
address = models.CharField(max_length=100)
dob = models.CharField(max_length=100)
salary = models.IntegerField
doj = models.DateField()
class Meta:
db_table = "test"
Here is my view.py:
def calender(request):
distinctyears = Persons.objects.all().values('doj').distinct()
year = {
"Items": distinctyears
}
return render(request, "home.html", year)
Here is my html :
<div>
{% for item in Items %}
<div class="numbers">{{ item.doj }}</div>
{% endfor %}
</div>
My code is not working. Any help will be highly appreciated.
Thank You!
You need to add .distinct([*fields]) at the end of your query.
Here's the difference. For a normal distinct() call, the database compares each field in each row when determining which rows are distinct. For a distinct() call with specified field names, the database will only compare the specified field names.
As stated all fields in a record are checked. Mostly likely in your case you are getting records with different field values (more likely a case if you are queries multiple tables ManyToMany or ForeignKey relations).

How to save address form data and display in template using Django

Brand new to Django/Python and have almost completed my first big project. I've built a small ecommerce store with a staff backend to update/delete and create products. I would like to display the address entered in by the User at checkout with in the Staff template.
My code so far looks like this:
models.py:
class Address(models.Model):
ADDRESS_CHOICES = (
('B', 'Billing'),
('S', 'Shipping'),
)
user = models.ForeignKey(
User, blank=True, null=True, on_delete=models.CASCADE)
street_address = models.CharField(max_length=150)
town_or_city = models.CharField(max_length=100)
county = models.CharField(max_length=100, default=True)
postcode = models.CharField(max_length=20)
address_type = models.CharField(max_length=1, choices=ADDRESS_CHOICES)
default = models.BooleanField(default=False)
def __str__(self):
return f"{self.street_address}, {self.town_or_city}, {self.county}, {self.postcode}"
class Meta:
verbose_name_plural = 'Addresses'
I would like to captcha the data from the 'street_address', 'town_or_city', 'county' and 'postcode' fields and have that info displayed with in my staff template.
The idea I had was to import my Address model and grab all objects using Address.objects.all() and have this display with in the template using something like {{ user_address}}
views.py / StaffView:
class StaffView(LoginRequiredMixin, generic.ListView):
template_name = 'staff/staff.html'
queryset = Order.objects.filter(ordered=True).order_by('-ordered_date')
paginate_by = 10
context_object_name = 'orders'
def get_address(self):
user_address = Address.objects.all()
return user_address
staff.html:
<tr>
<td><a class="order-ref-number-link" href="{% url 'cart:order-detail' order.pk %}">#{{ order.reference_number }}</a>
</td>
<td>{{ order.ordered_date }}</td>
<td>{{ order.user.email }}</td>
<td>£{{ order.get_total }}</td>
<td>{% if order.ordered %}Paid{% else %}Not Paid!{% endif %}</td>
<td>{{ user_address }}</td> <--HERE IS WHERE I'M TRYING TO DISPLAY ADDRESSES
</tr>
{% empty %}
So far this method i've tried alone returns nothing, im still finding my way around Django so would really appreciate if someone could help me find a simple solution for this. If any additional info is needed I'll be happy to provide. Thanks in advance.

Django Query Set to get Row value as column name

These are my models:
class Build(models.Model):
name = models.CharField(db_index=True, max_length=56)
description = models.TextField(max_length=512, null=True, blank=True)
class Case(models.Model):
name = models.CharField(db_index=True, max_length=255)
description = models.TextField(max_length=1024, null=True, blank=True)
class Result(models.Model):
status = models.CharField(max_length=12)
result_build = models.ForeignKey(Build, related_name='result_build', on_delete=models.CASCADE)
result_case = models.ForeignKey(Case, related_name='result_case', on_delete=models.CASCADE)
I need a django QuerySet to get data like below:
....................................................
: case_name : case_description : build_X : build_Y :
:...........:..................:.........:.........:
: test1 : case1 : PASS : FAIL :
: test2 : case2 : FAIL : PASS :
:...........:..................:.........:.........:
where case_name and case_description are fields from Case model.
build_X and build_Y are the two build names available in Build model
and PASS and FAIL are the status for different cases and builds from Result model.
This is a classical case for many-to-many relationship with a through model. The model classes can be refactored as following:
class Build(models.Model):
name = models.CharField(db_index=True, max_length=56)
description = models.TextField(max_length=512, null=True, blank=True)
class Case(models.Model):
name = models.CharField(db_index=True, max_length=255)
description = models.TextField(max_length=1024, null=True, blank=True)
builds = models.ManyToManyField('Build', through='Result', related_name='cases')
class Result(models.Model):
status = models.CharField(max_length=12)
build = models.ForeignKey('Build', on_delete=models.CASCADE)
case = models.ForeignKey('Case', on_delete=models.CASCADE)
We can also call the properties of Result simply build and case, without redundancy in the names. Although related_name doesn't bother, we don't really need it here.
Now you can use the m2m relationship to query your models:
case = Case.objects.get(pk=1) # get Case object with primary key 1
case.builds.all() # get all Build objects related to case
build = Build.objects.get(pk=1) # get Build object with primary key 1
build.cases.all() # get all Case objects related to build
# UPDATE
# get Result objects for the "case" with pk=1 retrieved before
results = Result.objects.filter(case=case)
# output each entry as row with all property values
for r in results:
print(r.case.name, r.case.description, r.build.name, r.build, description, r.status)
You can also use .filter to narrow down your query result.
EDIT:
Here is one possible way to create a matrix table. This is a code you can put in your view:
cases = Case.objects.all()
builds = Build.objects.all()
matrix = []
for c in cases:
result = {}
result['case'] = c
result['status'] = []
for b in builds:
result['status'].append(Result.objects.filter(
case=c,
build=b
).values_list('status', flat=True))
matrix.append(result)
Now you should have a table with a dictionary for every case. Pass builds and matrix as context to your template. Then you can iterate over the builds to create the table header (take care to leave space for a column or two in the beginning for listing the cases). Then iterate over the matrix and create the table body. First get the case for the first column (or the first two columns) and then output the status.
I hope this can point you the way. Once you have the right result you can further optimize the performance.
EDIT 2:
Here is an example how the table could look like.
Pass builds and matrix from the code snippet above as context to the template:
<table>
<tr>
<th>Case name</th>
<th>Case description</th>
{% for b in builds %}
<th>{{ b.name }}</th>
{% endfor %}
</tr>
{% for row in matrix %}
<tr>
<td>{{ row.case.name }}</td>
<td>{{ row.case.description }}</td>
{% for s in row.status %}
<td>{{ s.0 }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
In the first for loop we create a table header with two column headers for case name and case description and one column header for each build.
In the second for loop we create a table row for each case. In the nested loop we output the status.
It is a very simple approach and probably can be further optimized, but I leave that to you.

How can I establish grouping in Django through models?

I created a model named MenuItems which will allow for me to enter all of the items that a restaurant has on their menu, later I will use these on the front end. I also created a model name MenuGrouping so that on the front end, I can have Bootstrap tabs show the group_title and under each, show the items in that group. What field should I add in the MenuItems model to associate it to a group? I attempted to use group = models.ForeignKey(MenuGrouping) but then I run into the issue of showing each item in the specific group.
Models.py:
class MenuItems(models.Model):
menu_item_title = models.CharField(max_length=256)
menu_item_description = models.TextField()
menu_item_price = models.DecimalField(max_digits=4, decimal_places=2)
customer_favorite = models.BooleanField(default=False)
is_on_menu = models.BooleanField(default=True)
class Meta:
ordering = ('menu_item_title', )
class MenuGrouping(models.Model):
group_title = models.CharField(max_length=256)
Is there a relationship that I can add in the MenuGrouping model that I can associate multiple MenuItems?
Thank you in advance!
If I understand you correctly that you are trying to make groups like drink, food, desert and ... then here it is:
Each item can be only in one group (I mean soda is a drink and it can't be food too and etc). So what you need to do here is to add a field to MenuItems model.
your MenuItems should be like this:
class MenuItems(models.Model):
menu_item_title = models.CharField(max_length=256)
menu_item_description = models.TextField()
menu_item_price = models.DecimalField(max_digits=4, decimal_places=2)
customer_favorite = models.BooleanField(default=False)
is_on_menu = models.BooleanField(default=True)
group = models.ForeignKey(MenuGrouping)
Now to use this in your template first get the groups in view and send them to template and then:
{% for group in groups %)
# add your tabs or just print the group name. or how ever you want.
Group {{ group.group_title }}:
# and now you can list the items in this group here
{% for item in group.menuitems_set.all %}
Title is: {{ item.menu_item_title }}
Price is: {{ item.menu_item_price }}
...
{% endfor %}
{% endfor %}
If you need all items to be listed somewhere else out of groups or any other way just send the items to the template too.
Here is the Many to One relationship documentation :
Many-to-one relationships
Also you can add a m2m relation to MenuGrouping and add items to each group but then one item can be in multiple groups and for a restaurant menu I can't see how that might happen.

Iteration of instances inside controller and pass to context

I have started creating a personal expenses django app to learn python...
So far, I have written some models for categories, transactions, scheduled transactions (for example re-occuring bills), type of accounts etc. And I am stuck :)
What I am trying to do is to display all transactions in an html page. Those that re-occur, should be listed also, as my app displays all transactions you have until 365 days from now. I can't manage to display all instances of repeating transactions.
model
class Transaction(models.Model):
category = models.ForeignKey(Category)
kind = models.ForeignKey(Kind)
account = models.ForeignKey(Account)
userA = models.ForeignKey(User, related_name='userA')
userA_contribution = models.DecimalField(max_digits=9, decimal_places=2)
userB = models.ForeignKey(User, related_name='userB', blank=True, null=True)
userB_contribution = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
transaction_text = models.CharField(max_length=200)
transaction_date = models.DateTimeField('transaction date')
transaction_price = models.DecimalField(max_digits=9, decimal_places=2)
def __str__(self):
return self.transaction_text
# calculate days since transaction has been made
def days_ago(self):
days_ago = timezone.now() - self.transaction_date
return days_ago.days
class ScheduledTransaction(Transaction):
REPEATING_CHOICES = (
('0', 'Once'),
('1', 'Daily'),
('2', 'Every other day',),
('7', 'Every week'),
('14', 'Every two weeks'),
('30', 'Monthly'),
('90', 'Quarterly'),
('180', 'Six months'),
('365', 'Annually'),
)
repeated = models.CharField(max_length=30, choices=REPEATING_CHOICES)
def days_to_payment(self):
days_to_payment = self.transaction_date - timezone.now()
return days_to_payment.days
def cost_per_month(self):
cost_per_month = self.userA_contribution / int(self.repeated) * 30
return cost_per_month
controller
def index(request):
latest_transactions_list = Transaction.objects.all().order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
# create a list to save scheduleTransaction.object instances
s_instances = []
for sche in scheduled_transactions:
s_instances.append(sche)
next_payment_days = int(sche.repeated) # next payment day is the repeated value, e.g. = 30 days
base_trans_date = sche.transaction_date
while next_payment_days < 365:
sche.transaction_date = base_trans_date + datetime.timedelta(days=next_payment_days)
s_instances.append(sche)
next_payment_days = next_payment_days + int(sche.repeated)
accounts_dash = Account.objects.all().order_by('-name')
date_today = datetime.datetime.now()
context = { 'latest_transactions_list': latest_transactions_list,
'scheduled_transactions' : s_instances,
'accounts_dash' : accounts_dash,
'date_today' : date_today,
}
return render(request, 'transactions/index.html', context)
view
{% for strans in scheduled_transactions %}
{% if strans.repeated|add:0 <= 365 %}
<tr>
<td class="">{{ strans.transaction_date }}</td>
<td class="text-center"><span class="label label-default">{{ strans.kind }}</span></td>
<td class="text-center"><span class="label label-info">{{ strans.category }}</span></td>
<td class="text-center">{{ strans.transaction_text }}</td>
<td class="text-right">{{ strans.userA_contribution|floatformat:2 }}€</td>
<td class="text-center">{{ strans.repeated }}</td>
<td class="text-center">{{ strans.days_to_payment }}</td>
<td class="text-right">{{ strans.cost_per_month|floatformat:2 }}€</td>
</tr>
{% endif %}
{% endfor %}
The transaction is printed in the terminal webserver shell, but not displayed even once on the html.
Any help would be appreciated !
EDIT: Updated the controller. Now the iteration works, but I always get the latest date and the total of days_to_payment in all instances. Any ideas ?
Firstly, it's a view, not a controller.
Secondly, what you're doing with s_instances doesn't seem to make sense. First you declare it as global for no reason - it's local to the view function, so there's no need to make it global. Then you iterate through the transactions and for each one you redefine s_instances to be the value of the latest one. You should be appending to a list, not redefining it each time. And then you append two methods: days_to_payment and cost_per_month - without ever actually calling them. And finally, having converted your instances to a list of simple values, you attempt to call them from the template by their original property names, which they no longer have.
However, I must question why you think you need to do that at all. All the things you put into that list are simple model attributes or methods. Why not simply pass the transaction objects straight to the template? Then your template would actually work.
Just remove this useless and insane for loop from your view and you should be better:
def index(request):
latest_transactions_list = Transaction.objects.order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
accounts_dash = Account.objects.order_by('-name')
date_today = datetime.now()
context = {'latest_transactions_list': latest_transactions_list,
'scheduled_transactions': scheduled_transactions,
'accounts_dash': accounts_dash,
'date_today': date_today,
}
return render(request, 'transactions/index.html', context)

Categories