Handling Views and Foreign keys in Django - django-views

I have a simple model in models.py:
class Inspection(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
# сознание#
class Consciousness(models.Model):
inspection = models.ForeignKey(Inspection, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
def __str__(self):
return self.choice_text
And I have view.py, where I create context:
def Detail(request, inspection_id):
inspection = get_object_or_404(Inspection, pk=inspection_id)
consciousness = Consciousness.objects.get(inspection=inspection)
context = {'inspection':inspection, 'consciousness':consciousness}
return render(request, 'healthcare/detail.html', context)
To use it ine template:
<p>{{ inspection.name }}</p>
<p>{{ consciousness.choice_text }}</p>
But instead of result, I get:
Skin matching query does not exist
I guess the problem is in Views.py. I cannot really understand how to between object and object with foreign key.

In fact code is correct. Just object consciousness didn't exist, that's why I got an error. After creation of object, error disappears.
The next point is to handle with Skin matching doesn't exist.
I thank myself for answering the question.

Related

Can't insert Title of Category in HTML with Django

I want to display only the title of my Django Category in HTML, but don't know how to access it properly. For the Category I use the MPTT library.
My views.py looks like this:
def category_products(request,id,slug):
products = Product.objects.filter(category_id=id)
category = Category.objects.all()
context={'products': products,
'category':category,
'slug': slug}
return render(request,'sondermuenz/category_products.html',context)
The model
class Category(MPTTModel):
title = models.CharField(max_length=200)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
slug = models.SlugField(unique=True)
def __str__(self):
return self.title
class MPTTMeta:
order_insertion_by = ['title']
def __str__(self):
full_path = [self.title]
k = self.parent
while k is not None:
full_path.append(k.title)
k = k.parent
return ' -> '.join(full_path[::-1])
class Product(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(blank=True,null=True)
image = models.ImageField(....)
...
The urls:
path('products_13/<int:id>/<slug:slug>', views.category_products, name='products'),
When I insert in my html file this
<h1>{{ slug }}</h1>
I can show the passed in slug, but how can I display the title of the product or category?
If I loop through it will show the same amount of titles as the looped objects, but I want to display it only once.
I hope someone can help. Thank you.
The {{ slug }} you are rendering is coming from the context in your view:
context={'products': products,
'category':category,
'slug': slug}
This is where you specify the names of objects that you want to render in the template. Right now, categories and products in your template will both be querysets, or a list of objects from the Django ORM. If you want to show just the first category title you could modify the context in the view:
context = {'first_category': Category.objects.first().name}
Then you could use first_category in the template. Or you can use Jinja's logic in the template to accomplish the same goal, without modifying context:
{{ category.first.name }}
You can preprocess objects when setting up your view's context and make them formatted the way you wish, or use Jinja in the template - both work and can be used in conjunction.
Solved. I added cat = Category.objects.get(pk=id) in views, now i can call cat.title in the html.

Django - Reverse a queryset

I have very basic view with queryset, but for some reason I cannot reverse it.
def home(request):
posts = Post.objects.all().reverse()
return render(request, "home.html", {'posts': posts})
For some reason no matter how I change code - instanses from queryset always rendering in same order.
Below there are lines of code that I already tried and which didn't worked for some reason:
Post.objects.all().reverse()
Post.objects.order_by('-date')
Post.objects.order_by('date').reverse()
home.html:
{% for post in posts %}
{{ post.title }}
{{ post.content }}
{% endfor %}
models.py:
class Post(models.Model):
title = models.CharField(max_length=100, unique=True, blank=True, null=True)
image = models.URLField(blank=True, null=True, unique=True)
content = models.TextField(blank=True, null=True)
date = models.DateField(auto_now=False, auto_now_add=True)
#To make in name, not objXXX
def __str__(self):
return self.title
I believe the queryset you're looking for is Post.objects.all().order_by("-date"):
def home(request):
posts = Post.objects.all().order_by("-date")
return render(request, "home.html", {"posts": posts})
It is considered a best practice to avoid putting ordering on a Django model, as it can force unnecessary sorting operations in the database when you don't need them. When necessary, I put default ordering on Django Admin definitions, instead of the model. Good luck!
If it is the ordering that you are looking for try (in models.py):
class Meta:
ordering = ('-date',)
If not, it does not mean much to reverse something that isn't ordered, try (in views.py):
This
post = Post.objects.filter("<filter name>").reverse()
instead of
post = Post.objects.all.order_by("<field name>").reverse()

View returns 404 when including a queryset despite the object being valid

I'm using the following URL pattern to pass a primary key for a model to the view class detailed below it. The primary key of the related model, "Host", is either a valid IP address or FQDN.
URL Pattern:
ValidIpAddressRegex = "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
ValidHostnameRegex = "(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])"
url(r"^host/(?P<pk>({}|{}))/$".format(ValidIpAddressRegex, ValidHostnameRegex),
views.HostView.as_view(),
name="host")
View class:
class HostView(generic.DetailView):
model = Host
template_name = 'report_viewer/host.html'
context_object_name = 'related_findings'
def get_queryset(self):
"""Return all related findings"""
host = get_object_or_404(Host, name=self.kwargs["pk"])
return host.get_findings() # A function on the model to return related records from another model
Relevant template:
<ul>
{% for finding in related_findings %}
<li><strong>{{ finding.plugin_id }}</strong> {{ finding.plugin_name }}</li>
{% empty %}
<li>No findings!</li>
{% endfor %}
</ul>
Host model:
class Host(models.Model):
name = models.CharField(max_length=255, primary_key=True)
os_general = models.CharField(max_length=255, blank=True, verbose_name="Generic OS Identifier")
os_specific = models.CharField(max_length=255, blank=True, verbose_name="Reported OS Name")
ssh_fingerprint = models.CharField(max_length=255, blank=True, verbose_name="SSH Fingerprint")
mac_address = models.CharField(max_length=17, blank=True, verbose_name="MAC Address")
ip_address = models.GenericIPAddressField(blank=True, null=True, verbose_name="IP Address")
fqdn = models.CharField(max_length=255, blank=True, verbose_name="Fully Qualified Domain Name")
netbios_name = models.CharField(max_length=255, blank=True, verbose_name="NetBIOS Name")
def __str__(self):
return self.name
def get_findings(self):
findings = Finding.objects.filter(targets=self)
return findings
class Meta:
ordering = ['name']
The result of a valid URL is "No finding found matching the query", raised by views.HostView. The view below works successfully, invoking the {% empty %} condition, which suggests that I'm either constructing the get_object_or_404 request incorrectly, or perhaps the "pk" variable is being mangled and is not a valid key.
I'd appreciate any thoughts on a solution. Or indeed an alternative method to achieve the same outcome.
Turns out the solution was a great deal simpler than expected. I was attempting to use the get_queryset function with the generic DetailView, when it's meant to be used with ListView.
I rewrote the model to use the get_context_data function instead.
class HostView(generic.DetailView):
model = Host
template_name = 'report_viewer/host.html'
def get_context_data(self, **kwargs):
"""Return all related findings"""
context = super(HostView, self).get_context_data(**kwargs)
context['host'] = get_object_or_404(Host, name=self.kwargs["pk"])
context['findings'] = context['host'].get_findings()
return context
Which then allows me to access the relevant Host model and all its related Finding models in the template.

If haystack returns an object, why can't I use result.objects.get_absolute_url

I'm using haystack and I follow the tutorials. I add haystack to settings, migrate, then I create this
class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
publish = indexes.DateTimeField(model_attr='publish')
def get_model(self):
return Post
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
in templates I create
search/indexes/blog/post_text.txt
and add this to it
{{ object.title }}
{{ object.tags.all|join:", " }}
{{ object.body }}
in my views.py i add
from haystack.query import SearchQuerySet
then in a view function
def post_search(request):
form = request.GET.get('q')
results = SearchQuerySet().models(Post).filter(content=form)
# count total results
total_results = results.count()
template = 'blog/post/search.html',
context = {
'form': form,
'results': results,
'total_results': total_results
}
return render(request, template, context)
and in a search template
{% for result in results %}
<p>{{result.publish}}</p>
{{ result.object.title }}
but the only thing that gets returned is the publish. If I inspect the a element the href is blank. if I do this
{{results}}
I get something like this
[blog.post.pk(2)] or something like that
these will not work
{{result.object.publish}}<br>
but this will
{{result.publish}}
and to access these
{{result.object.body}}<br>
{{result.object.title}}<br>
{{result.object.slug}}<br>
I go back and add this
class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
publish = indexes.DateTimeField(model_attr='publish')
# added this
title = indexes.CharField(model_attr='title')
body = indexes.CharField(model_attr='body')
slug = indexes.CharField(model_attr='slug')
def get_model(self):
return Post
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
which is nothing like the the tutorials say What am I doing wrong?
I get my results buy doing this
result.title
not
result.object.title
and from the tutorials I watch and read all they do is this
class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
publish = indexes.DateTimeField(model_attr='publish')
def get_model(self):
return Post
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
but can access everything like this
result.object.title
result.object.publish
result.object.get_absolute_url
they are obviously accessing the whole object but for some reason I am not. any guidance or a suggestion to something that I could possibly see like a video
would be appreciated. I really don't get why I'm not accessing the whole object.
Edit :
my models.py
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
image = models.ImageField(null=True, blank=True)
author = models.ForeignKey(User,
related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
video = models.BooleanField(default=False)
video_path = models.CharField(max_length=320,
null=True,
blank=True,)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug])
objects = models.Manager() # The default manager.
published = PublishedManager() # Our custom manager.
tags = TaggableManager()
I'm using
Django==1.9.4
django-crispy-forms==1.6.0
django-haystack==2.4.1
django-taggit==0.18.0
Pillow==3.1.1
pysolr==3.4.0
pytz==2016.1
requests==2.9.1
python 3.5
Ive updated and rebuilt my schema and I followed Mike Hibbert and read a book called django by example follwed them verbatim and still cant figure it out. Is this some kinf=d of bug?
after researching this for about 3 day now, I have come across information that django 1.9 isnt fully supported so this may be the issue hopefully. Hope this spares someone the anguish that I've went through.
I had a similar or probably even the same problem.
For some reason, reverse lookups within my get_absolute_url method failed after I'd accessed the HaystackSearchQueryset containing the results. It seemed as though the reverse mechanism didn't have any patterns to analyze ("...patterns tried: []").
Your suggestion pointing towards Django 1.9 incompatibilities helped me a lot as I just installed the lastest master and everything seems to work just fine now.Django 1.9 compatibility was added here by Claude Peroz. Yay :-)

TypeError: 'method' object is not iterable

I get a TypeError when I use the following code in my Django Template:
{% for signature in petition.get_signatures %}
{% include 'petition/signature.html' with petition=petition %}
{% endfor %}
Here are my models and classes:
class Petition(models.Model):
title = models.CharField(max_length= 90, default="Enter petition title here")
created_on = models.DateTimeField(auto_now_add=True)
image = models.ImageField(null=False, upload_to='static/petition-photos/%Y/%m/%d')
video = models.CharField(max_length=600, default="Enter an external video link")
petition = models.TextField(null=False, default="Type your petition here")
created_by = models.ForeignKey(User)
def total_likes(self):
return self.like_set.count()
def __str__(self):
return self.title[:50]
def get_signatures(self):
return self.signature_set.all
class Signature(models.Model):
petition= models.ForeignKey(Petition)
user = models.ForeignKey(User)
description = models.TextField(null=False, blank=False)
anonymous = models.BooleanField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.petition
I get the following error message when I load my template view page with the 'for' condition. The error message I get is 'method' object is not iterable. What might I be doing wrong? Any solutions? I'm kind of a noob so if you could explain the solution too, that would be great.
You need to call the .all() method:
def get_signatures(self):
return self.signature_set.all()
You returned the method object itself, rather than the result it produces when called, and the {% for signature in .. loop tries to iterate over that method object, and can't.