models.py
class ReportType(models.Model):
report = models.ForeignKey(Report)
title = models.CharField('Incident Type', max_length=200)
class Report(models.Model):
user = models.ForeignKey(User, null=False)
app_uuid = models.CharField('Unique App Id', max_length=100)
class Types(models.Model):
user = models.ForeignKey(User, null=True)
title = models.CharField('Incident Type', max_length=200)
is_active = models.BooleanField('Is Active', default=True)
In Types table,i am saving some default data in title field.The data entered by user are saved in ReportType table.
I want to compare the data in title field in Types model and ReportType model.After comparison,if title field data in ReportType model is not present in Types model,i need to display that in template.I need to show the non matching value present in ReportType model.
template.html
{% for type in report_type %}
{{type.title}}{% endfor %}
I tried with this query
report_type = Report.objects.filter(reporttype__title=F('types__title'))
I am getting this error "Cannot resolve keyword 'types' into field",this is because Types table don't have relation with Report table.Need help.
It seems you need at least 2 queries then:
# get all types as a list
all_types = Types.objects.values_list('title', flat=True)
# you need to show the mismatch, then use exclude()
report_type = ReportType.objects.exclude(title__in=all_types)
Hope it helps.
You can filter ReportType objects and get Reports from result queryset like this:
ReportType.objects.values_list('report').filter(title__in=Types.objects.values_list('title', flat=True).distinct())
Related
I am using .values() and .annotate()to sum up 2 models fields based on matching criteria.
I wrapped this in a forloop in my template to iterate.
Problem: I cannot call the model fields anymore. The forloop returns the venue_id instead of the name and the usual approach to call the logo does not work anymore.
(these were rendering fine before I used .values() and .annotate(). Makes me think I am missing something in the logic here. Any ideas?
Models
class Venue(models.Model, HitCountMixin):
id = models.AutoField(primary_key=True)
name = models.CharField(verbose_name="Name",max_length=100, blank=True)
logo = models.URLField('Logo', null=True, blank=True)
class Itemised_Loyatly_Card(models.Model):
user = models.ForeignKey(UserProfile, blank=True, null=True, on_delete=models.CASCADE)
venue = models.ForeignKey(Venue, blank=True, null=True, on_delete=models.CASCADE)
add_points = models.IntegerField(name = 'add_points', null = True, blank=True, default=0)
use_points = models.IntegerField(name= 'use_points', null = True, blank=True, default=0)
Views
from django.db.models import Sum, F
def user_loyalty_card(request):
itemised_loyalty_cards = Itemised_Loyatly_Card.objects.filter(user=request.user.id).values('venue').annotate(add_points=Sum('add_points')).annotate(use_points=Sum('use_points')).annotate(total=F('add_points')-F('use_points'))
return render(request,"main/account/user_loyalty_card.html", {'itemised_loyalty_cards':itemised_loyalty_cards})
Templates
{%for itemised_loyatly_card in itemised_loyalty_cards %}
<img"src="{{itemised_loyatly_card.venue.logo}}">
{{itemised_loyatly_card.venue}}
{{itemised_loyatly_card.total}}
{%endfor%}
Renders
It returns only the value ID because that is the only field you passed in as an argument to .values('venue'). Whereas if you want another attribute you have to use field lookups, like so:
.values('venue__name'. 'venue__logo')
Also, .values() returns a QuerySet that returns dictionaries and not object instances, so if you pass that data into the template you can not access related data, meaning
{{itemised_loyatly_card.venue.logo}} will not work, but taking the first codeblock as an example {{itemised_loyatly_card.venue__logo}} works.
Another "mistake" is at these two annotations, annotations are a per object aggregation, these two lines are redundant, your model already has these fields.
.annotate(add_points=Sum('add_points'))
.annotate(use_points=Sum('use_points'))
That being said, if you want objects instead of values, that leaves you with:
views.py
itemised_loyalty_cards = (
Itemised_Loyatly_Card.objects.filter(user=request.user.id)
.annotate(total=F('add_points')-F('use_points'))
)
template.html
{%for itemised_loyatly_card in itemised_loyalty_cards %}
<p>
{{itemised_loyatly_card.venue.name}}
{{itemised_loyatly_card.add_points}}-
{{itemised_loyatly_card.use_points}}=
{{itemised_loyatly_card.total}}
</p>
<img src="{{itemised_loyatly_card.venue.logo}}" alt="" >
{%endfor%}
I have the following models:
# Get or create a 'Not selected' category
def get_placeholder_categoy():
category, _ = ListingCategories.objects.get_or_create(category='Not selected')
return category
# Get default's category ID
def get_placeholder_category_id():
return get_placeholder_categoy().id
class ListingCategories(models.Model):
category = models.CharField(max_length=128, unique=True)
def __str__(self):
return f'{self.category}'
class Listing(models.Model):
title = models.CharField(max_length=256)
seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name='listings')
description = models.TextField(max_length=5120, blank=True)
img_url = models.URLField(default='https://media.istockphoto.com/vectors/no-image-available-picture-coming-soon-missing-photo-image-vector-id1379257950?b=1&k=20&m=1379257950&s=170667a&w=0&h=RyBlzT5Jt2U87CNkopCku3Use3c_3bsKS3yj6InGx1I=')
category = models.ForeignKey(ListingCategories, on_delete=models.CASCADE, default=get_placeholder_category_id, related_name='listings')
creation_date = models.DateTimeField()
base_price = models.DecimalField(max_digits=10, decimal_places=2, validators=[
MinValueValidator(0.01),
MaxValueValidator(99999999.99)
])
With these, I have the following form:
class ListingForm(ModelForm):
class Meta:
model = Listing
exclude = ['seller', 'creation_date']
widgets = {
'title': TextInput(attrs=base_html_classes),
'description': Textarea(attrs=base_html_classes),
'img_url': URLInput(attrs=base_html_classes),
'category': Select(attrs=base_html_classes),
'base_price': NumberInput(attrs=base_html_classes)
}
One of the available categories I have is "Not selected", since I want to allow that if at some point a category were to be removed, items can be reassigned to that one, however, when rendering the form, I will do some validation on the view function to prevent it from being submitted if the "not selected" category is sent with the form.
Because of this, I want the HTML form on the template to assign the 'disabled' attribute to the option corresponding to that category, however, I have been searching for a couple of days now without finding anything that I was able to understand to the point where I could try it.
Ideally, another thing I'd like to achieve is to be able to modify the order of the rendered options on the form so that I can move to the top 'not selected' regardless of its primary key within the model.
I am aware I can just create a form instead of a model form, or just modify the template so I manually specify how to render the form itself, but I do feel like there is a simple fix to this either on the model or on the model form that I am just not finding yet.
Thanks in advance!
I would suggest you use (in model definition)
class Listing(models.Model):
..
category = model.ForeignKey(ListingCategories, on_delete=models.SET_NULL, null=True, related_name='listings')
..
and optionally in form definition
class ListingForm(ModelForm):
category = forms.ModelChoiceField(ListingCategories, empty_label='Not Selected')
..
While rendering model form, a required attribute will be automatically added, and in form validating, it is also required. It is only in database validation that the field can be left NULL
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).
I have a model where I am using Enum for choices:
class Agreement(models.Model):
class Category(enum.Enum):
EULA = 0
PROVIDER = 1
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
category = models.IntegerField(
choices=[(choice.name, choice.value)
for choice in Category])
title = models.CharField(max_length=128)
content = models.TextField()
I register it using simple admin site registration:
admin.site.register(Agreement)
When admin site renders the object it doesn't allow me to save it? Has anyone had a similar issue?
According to the documentation:
The first element in each tuple is the actual value to be set on the model, and the second element is the human-readable name.
name and value should be the other way around, like this:
category = models.IntegerField(
choices=[(choice.value, choice.name)
for choice in Category])
because category is an integer field and name returns a string.
I have a situation where I would like to loop over all the tables available in database(stored in models.py) and print the meta attribute verbose_name only for tables having this attribute in the django html template. .This way the user can select the tables he want to view.
I have tried a few methods, but none seem to work..
This is my code :-
def tables_select(request):
if request.user.is_authenticated():
mdls = models.get_models(include_auto_created=False)
tables_list = [mdl._meta.verbose_name for mdl in mdls]
return render(request, 'cbm/tables_select.html', {'tables_list': tables_list})
else :
...
a check using hasattr() method doesn't work either :
for mdl in mdls:
if (hasattr(mdl._meta, 'verbose_name')):
tables_list.append(mdl._meta.verbose_name)
For the tables not having the verbose_name parameter, both of them return actual db table name.
UPDATE: These are the 2 model definitions in models.py :
This is the master table
class Ai(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
well = models.ForeignKey('Well', db_column='Well_ID')
samplename = models.CharField(db_column='sampleName', max_length=40, blank=True)
startdepth = models.FloatField(db_column='startDepth', blank=True, null=True)
... # Plus some other Columns
def __unicode__(self):
return self.samplename
class Meta:
managed = False
db_table = 'ai'
verbose_name = "Adsorbtion Isotherm"
AichIo is a dependent table on Ai
class Aich4Io(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
ai = models.ForeignKey(Ai, db_column='AI_ID')
pressurekpa = models.IntegerField(db_column='pressureKPa', blank=True, null=True)
pressureatm = models.FloatField(db_column='pressureAtm', blank=True, null=True)
meccreported = models.FloatField(db_column='meccReported', blank=True, null=True)
dafccreported = models.FloatField(db_column='dafccReported', blank=True, null=True)
class Meta:
managed = False
db_table = 'aich4io'
I don't want the names of dependent tables to be printed.
However for my html template:
{% for table in tables_list %}
{{ table }}<br>
{% endfor %}
The output is:
Adsorbtion Isotherm
aich4 io
After much research/combinations was able to find out this is generic behavior of django.
For models not having verbose_name parameter, the table/model name is returned as string.
To achieve my objective, I added verbose_name = 'DNS' for the models for which I didn't want to display the verbose_name. And in my code i did something like:
if mdl._meta.verbose_name == 'DNS':
# Do Nothing
else:
# My Logic.
You can check what type the verbose name is. If it's unicode then you can print the name
mdls = models.get_models(include_auto_created=False)
for mdl in mdls:
if isinstance(mdl._meta.verbose_name, unicode):
print mdl._meta.verbose_name