How to get access to different models in the template? - django

I have 3 models
Do I need to change connections in the models, and make the key field not an id, but a name?
class Category(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.CharField(max_length=250)
class Company(models.Model):
name = models.CharField(max_length=150, unique=True)
country = models.CharField(max_length=50)
class Motobike(models.Model):
name = models.CharField(max_length=150)
company = models.ForeignKey('Company', on_delete=models.CASCADE)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
And tests:
def test_category(setup):
client = Client()
category_id = Category.objects.get(name='Мотоциклы').id
response = client.get(f'/categories/{category_id}/')
assert response.status_code == 200
response_data = json.loads(response.content.decode('utf-8'))
assert len(response_data) == 2
assert response_data[1]['name'] == 'Ninja Turbo'
assert response_data[1]['vendor'] == 'Kawasaki'
assert response_data[1]['category'] == 'Мотоциклы'
assert response_data[1]['description'] == ''
response = client.get(f'/categories/25/')
assert response.status_code == 404
In view I do so:
class CategoryView(DetailView):
model = Category
template_name = 'bikes_site/categories_detail.html'
def get_context_data(self, id, **kwargs):
context = get_object_or_404(self.model, id)
context['motobikes'] = Motobike.objects.filter(category_id=id).all()
return context
I get an error:
get_context_data() missing 1 required positional argument: 'id'

The function signature for get_context_data is wrong it should be
def get_context_data(self, **kwargs):
//todo
your detail view should like this
class CategoryView(DetailView):
model = Category
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = "id"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return context

Related

How to pass data (specific fiiled) from views.py to models.py

I have a problem. How can i pass the data (def maybe) from models.py
I need this for filter by category in future
class Tag(models.Model):
.......
category = models.ForeignKey(Category, null=True, on_delete=models.PROTECT, related_name='category', verbose_name='Tag category')
......
def get_category(self):
return self.category
To views.py. This is it doesn't work
class GetDetailTag(DetailView):
model = Tag
template_name = 'main/catalog.html'
context_object_name = 'tag'
category = Tag.get_category
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs,)
context['pansion_in_tag_list'] = Pansions.objects.filter(tags__slug=self.kwargs['slug'])
context['tags_in_category'] = Tag.objects.filter(category__slug = '...INSERT THE DATA FROM MODEL HERE...')
return context
I was trying to call the 'def'(get_category) in views.py
Anyway? How i can to do that?
You can just obtain this from the tag, so:
{{ tag.category }}
or in the DetailView:
class TagDetailView(DetailView):
model = Tag
template_name = 'main/catalog.html'
context_object_name = 'tag'
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['pansion_in_tag_list'] = Pansions.objects.filter(
tags__slug=self.kwargs['slug']
)
context['tags_in_category'] = Tag.objects.filter(
category_id=self.object.category_id
)
# category = self.object.category (obtain the category)
return context

apply a filter to the choices field of my model

Hi I have problems with some filters in django.
I have my own view where I can choose the day of the week which is a select choice field
once chosen it is saved in the db.
I would like to filter those already present so as not to repeat them if I had to choose another day.
Can anyone help me out please?
models.py
class Piano(models.Model):
nome_piano = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente_piano = models.ForeignKey(
User,
on_delete = models.CASCADE,
related_name = 'utente_piano'
)
def __str__(self):
return self.nome_piano
class Meta:
verbose_name = "Piano alimentare"
verbose_name_plural = "Piani alimentari"
class PianoSingleDay(models.Model):
giorni_settimana_scelta = [
("1","Lunedì"),
("2","Martedì"),
("3","Mercoledì"),
("4","Giovedì"),
("5","Venerdì"),
("6","Sabato"),
("7","Domenica")
]
giorni_settimana = models.CharField(
choices = giorni_settimana_scelta,
max_length = 300
)
single_piano = models.ForeignKey(
Piano,
on_delete = models.CASCADE,
related_name = 'single_piano'
)
def __str__(self):
return self.giorni_settimana
class Meta:
verbose_name = "Piano singolo"
verbose_name_plural = "Piani singoli"
views.py
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id = id, utente_piano = request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, prefix = 'giorno')
if giorno_form.is_valid():
day_piano = giorno_form.save(commit = False)
day_piano.single_piano = piano
day_piano.save()
return redirect('gestione-piano', id = piano.id)
else:
giorno_form = PianoSingleDayForm(prefix = 'giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)
forms.py
class PianoSingleDayForm(forms.ModelForm):
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
1
2
You can let the PianoSingleDayForm exclude the days that have already been selected for that Piano with:
class PianoSingleDayForm(forms.ModelForm):
def __init__(self, *args, piano=None, **kwargs):
super().__init__(*args, **kwargs)
if piano is not None:
days = set(PianoDaySingle.objects.filter(
single_piano=piano
).values_list('giorni_settimana', flat=True))
self.fields['giorni_settimana'].choices = [
(k, v)
for k, v in self.fields['giorni_settimana'].choices
if k not in days
]
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
We can then use this in the view by passing the Piano object to the form both in the GET and POST codepath:
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id=id, utente_piano=request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, piano=piano, prefix='giorno')
if giorno_form.is_valid():
giorno_form.instance.single_piano = piano
giorno_form.save()
return redirect('gestione-piano', id=piano.id)
else:
giorno_form = PianoSingleDayForm(piano=piano, prefix='giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)

I have problems with views

I have this models:
Class Category(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.CharField(max_length=250)
def get_absolute_url(self):
return reverse('categories_url', args=[str(self.id)])
class Company(models.Model):
name = models.CharField(max_length=150, unique=True)
country = models.CharField(max_length=50)
class Motobike(models.Model):
name = models.CharField(max_length=150)
company = models.ForeignKey('Company', on_delete=models.CASCADE)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
def get_absolute_url(self):
return reverse('details_url', args=[str(self.id)])
And views:
class CategoryView(DetailView):
model = Motobike
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = 'pk'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return context
And test:
def test_category(setup):
client = Client()
category_id = Category.objects.get(name='Мотоциклы').id
response = client.get(f'/categories/{category_id}/')
assert response.status_code == 200
response_data = json.loads(response.content.decode('utf-8'))
assert len(response_data) == 2
assert response_data[1]['name'] == 'Ninja Turbo'
assert response_data[1]['vendor'] == 'Kawasaki'
assert response_data[1]['category'] == 'Мотоциклы'
assert response_data[1]['description'] == ''
response = client.get(f'/categories/25/')
assert response.status_code == 404
I need to present all thin in JSON, through JsonResponce, and what should almost go to the meaning of the dictonary, did i create them correctly?
You should do something like in your view:
from django.http import JsonResponse
class CategoryView(DetailView):
model = Motobike
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = 'pk'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return JsonResponse(context, status=200) # or wahtever status is appropriate
Note: Haven't tested it, but that's what I use with GenericAPIView

Use sessions to count pageviews django detailview

I am trying to count the visits to a view. I would like for the counter to increment by 1 every time someone calls up the view. Then, I want the "visits" field on the model to automatically update with the latest count. However, I am not sure how to implement this. Using some code I've found, I am trying this:
models.py
class Statute(models.Model):
address = models.ForeignKey(Address,
null = True)
statute_name = models.CharField(max_length=25,
default='')
category = models.CharField(max_length=55,
default='')
section_number = models.CharField(max_length=55,
default='')
section_title = models.CharField(max_length=255,
default='')
timestamp = models.DateTimeField(editable=False)
visits = models.IntegerField(default=0)
content = models.TextField(default='')
slug = models.SlugField()
views.py
def get_context_data(self, **kwargs):
context = super(LibraryInStateView, self).get_context_data(**kwargs)
state = State.objects.get(slug=self.kwargs.get('state'))
statute = Statute.objects.all()
context['latest_statutes'] = statute.filter(
address__zipcode__city__county__state=state).order_by(
'-timestamp')
context['statute_count'] = Statute.objects.filter(
address__zipcode__city__county__state=state).count()
context['view_count'] = self.request.session['visits']+1
return context
You can include it in .get_object() method in LibraryInStateView
def get_object(self):
statute = super().get_object()
statute.visits += 1
statute.save()
self.view_count = statute.visits
return statute
Or get method:
def get(self, request, *args, **kwargs):
statute = # ... code to retrieve Statute for this view
statute.visits += 1
statute.save()
self.view_count = statute.visits
return super().get(request, *args, **kwargs)
Then once you attached view_count to class instance, you can add it to context:
def get_context_data(self, **kwargs):
...
context['view_count'] = self.view_count
return context
In your view update:
statute = Statute.objects.filter(address__zipcode__city__county__state=state)
statute.visits += 1
statute.save()
context['statute_count'] = statute

form.is_valid method keeps failing

I'm trying to make an editing page for the users to update an object data. However, form.is_valid() keeps failing, I have no idea why.
My model:
class Thread(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(max_length=10000)
USER_TYPES = (
('INI','Iniciante'),
('INT','Intermediário'),
('AVA','Avançado')
)
user_type = models.CharField(max_length=20, choices = USER_TYPES, default='INI')
category = models.ForeignKey(Category)
orcamento = models.IntegerField(default=0)
slug = models.SlugField(max_length=40, unique=True)
def get_absolute_url(self):
return "/%s/" % self.slug
def __str__(self):
return self.title
def save(self, **kwargs):
slug_str = "%s %s" % (self.category, self.title)
unique_slugify(self, slug_str)
super(Thread, self).save(**kwargs)
My view:
def edit_thread(request, thread_slug):
thread = Thread.objects.get(slug=thread_slug)
if request.method == 'POST':
form = EditThread(request.POST)
if form.is_valid():
thread.title = form.cleaned_data['title']
thread.orcamento = form.cleaned_data['orcamento']
thread.user_type = form.cleaned_data['experiencia']
thread.body = form.cleaned_data['pergunta']
thread.save()
return HttpResponseRedirect('/thread' + thread.get_absolute_url())
else:
data = {'title' : thread.title, 'experiencia':thread.user_type, 'orcamento' : thread.orcamento, 'pergunta': thread.body}
form = EditThread(initial=data)
return render(request, 'edit_thread.html', {
'form': form })
My form:
class EditThread(forms.ModelForm):
title = forms.CharField(label='Título', max_length=200, error_messages=my_default_errors)
orcamento = forms.IntegerField(label='Preço máximo', error_messages=my_default_errors)
experiencia = forms.ChoiceField(label='Você é um usuário...', choices=Thread.USER_TYPES, error_messages=my_default_errors)
pergunta = forms.CharField(label='Pergunta', widget=forms.Textarea, error_messages=my_default_errors)
class Meta:
model = Thread
def __init__(self, *args, **kwargs):
super(EditThread, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Div('title',
'experiencia',
PrependedAppendedText('orcamento', 'R$', ',00', active=True),
'pergunta',
FormActions(
Submit('save', 'Salvar alterações'),
)))
When accessing the page, the form gets pre-populated with the object's data as it should.
Your form should be inherited from the simple forms.Form instead of the forms.ModelForm:
class EditThread(forms.Form):
...
I would suggest you look at django's class based UpdateView. It can generate an update form for you or you could give it a custom ModelForm by overriding the form_class attribute on your view. When using a ModelForm, you also have to specify which model the form is for eg:
class EditThread(forms.ModelForm):
"field definitions ..."
class Meta:
model = Thread
fields = ['my_field_1', 'my_field_2']