Use sessions to count pageviews django detailview - django

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

Related

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

How to get access to different models in the template?

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

Creating an ID that rolls over by year

I have an invoice app that has an ID. I'd like to have it rollover by year. That is, every year, it would start back at 001. My return string would be 2014-001, 2014-002, 2015-001...
However, Django doesn't seem to support composite keys. Is there a way to do this?
class Invoice(models.Model):
description = models.CharField(max_length=200)
date = models.DateField('Date Issued')
client = models.ForeignKey('organizations.Contact')
UNPAID = 'Unpaid'
PAID = 'Paid'
STATUS_CHOICES = (
(UNPAID, 'Unpaid'),
(PAID, 'Paid'),
)
status = models.CharField(max_length=6,
choices=STATUS_CHOICES, default=UNPAID)
notes = models.TextField(blank=True)
def __str__(self):
return (self.date.__str__().replace("-", "") +
"-" + self.id.__str__().zfill(3))
edit new code:
def save(self, *args, **kwargs):
if self.invoice_id is "":
current_date = self.date.year
previous_invoice = Invoice.objects.filter(invoice_id__contains=current_date).order_by('-id').first()
if previous_invoice is not None:
num = int(previous_invoice.invoice_id[5:])
else:
num = 1
self.invoice_id = '{year}-{num:03d}'.format(year=current_date, num=num)
super(Invoice, self).save(*args, **kwargs)
You can use a CharField for the id, setting it as primary key and generating it automatically upon saving.
Something similar to the following should work:
class Invoice(models.Model):
id = models.CharField(max_length=8, null=False, primary_key=True)
...
def save(self, *args, **kwargs):
if self.pk is None:
current_year = datetime.now().year
previous_invoice = Invoice.objects.filter(id__contains=str(year)).order_by('-id').first()
if previous_invoice is not None:
num = int(previous_invoice.id[5:])
else:
num = 1
self.pk = '{year}-{num:03d}'.format(year=current_year, num=num)
super(Invoice, self).save(*args, **kwargs)
EDIT: Add missing primary_key attribute in id field definition.

Django ValueError when trying to save ManyToMany Values from a Form

I get the error "" needs to have a value for field "dataset" before this many-to-many relationship can be used." when trying to assign values to a ManyToMany field in my views. I've looked at many related questions here on SO that say I must save my Dataset object first. I think I am doing that...what is going wrong?? My database already contains four Subject items.
models.py
class Subject(TimeStampedModel):
subject_type = models.CharField(max_length=128, blank=False)
def __unicode__(self):
return self.subject_type
class Dataset(TimeStampedModel):
dataset_id = models.CharField(max_length=256)
dataset_doi = models.CharField(max_length=15)
dataset_name = models.CharField(max_length=256, blank=False)
dataset_description = models.TextField(blank=False)
lab = models.CharField(max_length=256, blank=False)
biological_sample = models.CharField(max_length=256, blank=False)
subject_type = models.ManyToManyField('Subject', related_name='datasets', blank=True)
date_collected = models.DateField(blank=True)
collection_facility = models.ManyToManyField('CollectionFacility', related_name='datasets', blank=True)
processing_notes = models.TextField(blank=True)
release_date = models.DateField()
release_asap = models.BooleanField()
pdb_code = models.CharField(max_length=256, blank=True)
publication_link = models.URLField(blank=True)
def create_name(self):
self.dataset_name = "%s %s" % (self.biological_sample, self.lab)
def save(self, *args, **kwargs):
self.dataset_id = self.id
def __unicode__(self):
return "%s : %s" % (self.dataset_name, self.dataset_id)
forms.py RegistrationForm:
class RegistrationForm(forms.Form):
subject_type = forms.ModelMultipleChoiceField(
label="Subject",
queryset = Subject.objects.all(),
widget=forms.CheckboxSelectMultiple(),
required = True,
)
views.py
def create_registration(form):
dataset = Dataset()
dataset.DOI = "preUpload"
dataset.lab = form.cleaned_data['lab']
dataset.biological_sample = form.cleaned_data['sample']
dataset.resource_type = form.cleaned_data['dataset_type']
dataset.dataset_description = form.cleaned_data['dataset_description']
dataset.date_collected = form.cleaned_data['date_collected']
dataset.release_date = form.cleaned_data['release_date']
dataset.release_asap = form.cleaned_data['release_asap']
if form.cleaned_data['pdb_code']:
dataset.pdb_code = form.cleaned_data['pdb_code']
if form.cleaned_data['publication_link']:
dataset.publication_link = form.cleaned_data['publication_link']
dataset.create_name()
dataset.save() # I don't think this save is working?
subjects = form.cleaned_data['subject_type']
dataset.subject_type = [x for x in subjects]
for facility in form.cleaned_data['facility']
dataset.collection_facility.add(facility)
dataset.save()
return dataset
def registration_submit(request):
registration_form = RegistrationForm(request.POST)
if registration_form.is_valid():
registration = create_registration(registration_form)
.......
You forgot to call the original save() in the overriden Dataset.save() method.
def save(self, *args, **kwargs):
self.dataset_id = self.id
super(Dataset, self).save(*args, **kwargs)

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']