I am quiet new to Django and I come from ASP.Net background.
I am trying to achieve OOP concept in one of the web application.
I have a model which maintains a movie list
url.py
from movies import views
url(r'^recent/$', views.recentlyadded)
models.py
from django.db import models
class MovieManager(models.Model):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
class Movie(models.Model):
movieid = models.AutoField(primary_key=True)
title = models.CharField(max_length=250)
objects = MovieManager()
I am trying to return the movie titles based on the keyword using custom manager MovieManager
views.py
from movies.models import Movie
def recentlyadded(request):
r = Movie.objects.title_count('night')
return HttpResponse("test")
This throws error AttributeError: 'Manager' object has no attribute 'title_count'
How to call models.py method in recentlyadded view.py function?
I want to use recentlyadded() method in multiple views/ functions in view.
The view code is correct, but not the model - MovieManager should inherit from models.Manager, not from models.Model. Not finding an explicitely declared Manager, the metaclass overwrite Movie.objects with a default manager.
FWIW you could have found out by yourself by inspecting Movie.objects in a Python shell (or by reading the source code for django.db.models.base.ModelBase).
To return the movie title. You probably would have this one the model.py file
Do it at the end if the model file
def __unicode__(self):
return self.title
Related
I have a model which creates Memo objects. I would like to use a custom Model Manager's posted method to return the total number of Memo objects - then use this number within a template. I am trying to keep as much of my code as possible within my Models and Model Managers and less within my Views as I read that this was a best practice in 'Two Scoops of Django'.
In the shell I can get the number of memos as such:
>>> from memos.models import Memo
>>> Memo.objects.all()
<QuerySet [<Memo: Test Memo 2>, <Memo: Test Memo 1>]>
>>> Memo.objects.all().count()
2
This is what my Model and Model Manager look like:
class MemoManager(models.Manager):
use_for_related_fields = True
def posted(self):
return self.count()
class Memo(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_time = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
objects = MemoManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('memos-detail', kwargs={'pk': self.pk})
I know this is clearly the wrong way to do it but I have confused myself here. So how do I use my Model Manager to get the count of objects and use it in a template like: {{ objects.all.count }}?
P.S. I see other posts that show how to do this within the view but as stated I am trying not to use the view. Is using the view required? I also understand my posted method is written incorrectly.
I'm sorry but you have misinterpreted what was written in TSD. The Lean View Fat Model is meant to keep code which pertains to 'business logic' out of the views, and certain model specific things. A request should be handled by a view. So when you want to load a template, you must first have a GET request to your app.
A view function should be written such that Validation of POST data or the Creation of a new object in DB or Querying/Filtering for GET requests should be handled in the corresponding serializer/model/model manager.
What should be happening while you want to load your template.
Have a url for the template that you have created and a view function mapped for it
In the view function you should render said template and pass the necessary data inside the context.
To keep in line with the Lean View Fat Model style, if you want to get a Queryset of of Memo's but only those which have their is_deleted fields set to False, you can overwrite the model manager get_queryset() method for Memo model.
If you want to create a new Memo with a POST request, you can handle
the creation using a ModelForm!
Hope this clears things up!
EDIT:
How to pass a context to a template, in your case the memo count.
def random_memo_view(request):
context = {'memo_count': Memo.posted()}
return render(request, 'template.html', context=context)
RE-EDIT
I just checked that you were using DetailView. In this case follow this from the django docs.
Class Based Views: Adding Extra Context
I'm writing a web scraper to get information about customers and appointment times to visit them. I have a class called Job that stores all the details about a specific job. (Some of its attributes are custom classes too e.g Client).
class Job:
def __init__(self, id_=None, client=Client(None), appointment=Appointment(address=Address(None)), folder=None,
notes=None, specific_reqs=None, system_notes=None):
self.id = id_
self.client = client
self.appointment = appointment
self.notes = notes
self.folder = folder
self.specific_reqs = specific_reqs
self.system_notes = system_notes
def set_appointment_date(self, time, time_format):
pass
def set_appointment_address(self, address, postcode):
pass
def __str__(self):
pass
My scraper works great as a stand alone app producing one instance of Job for each page of data scraped.
I now want to save these instances to a Django database.
I know I need to create a model to map the Job class onto but that's where I get lost.
From the Django docs (https://docs.djangoproject.com/en2.1/howto/custom-model-fields/) it says in order to use my Job class in the Django model I don't have to change it at all. That's great - just what I want. but I can't follow how to create a model that maps to my Job class.
Should it be something like
from django.db import models
import Job ,Client
class JobField(models.Field):
description = "Job details"
def __init__(self, *args, **kwargs):
kwargs['id_'] = Job.id_
kwargs['client'] = Client(name=name)
...
super().__init__(*args, **kwargs)
class Job(models.Model):
job = JobField()
And then I'd create a job using something like
Job.objects.create(id_=10101, name="Joe bloggs")
What I really want to know is am I on the right lines? Or (more likely) how wrong is this approach?
I know there must be a big chunk of something missing here but I can't work out what.
By mapping I'm assuming you want to automatically generate a Django model that can be migrated in the database, and theoretically that is possible if you know what field types you have, and from that code you don't really have that information.
What you need to do is to define a Django model like exemplified in https://docs.djangoproject.com/en/2.1/topics/db/models/.
Basically you have to create in a project app's models.py the following class:
from django import models
class Job(models.Model):
client = models.ForeignKey(to=SomeClientModel)
appointment = models.DateTimeField()
notes = models.CharField(max_length=250)
folder = models.CharField(max_length=250)
specific_reqs = models.CharField(max_length=250)
system_notes = models.CharField(max_length=250)
I don't know what data types you actually have there, you'll have to figure that out yourself and cross-reference it to https://docs.djangoproject.com/en/2.1/ref/models/fields/#model-field-types. This was just an example for you to understand how to define it.
After you have these figured out you can do the Job.objects.create(...yourdata).
You don't need to add an id field, because Django creates one by default for all models.
I'm wondering if there is a way in Wagtail to enter a custom template path via CharField in a base model, and then establish a template in an inherited model that would be the default. For example:
base/models.py
class WebPage(Page):
template_path = models.CharField()
def get_template(self, request):
if self.template_path:
template = template_path
else:
template = *something*
app/models.py
class MyWebPage(WebPage):
template = 'default_template.html'
Ideally, I'd establish the template attribute in the MyWebPage model, and that would act as a default. However, the get_template method in the WebPage base model would supersede it, but only if it's not empty. Is any of this possible?
I was reading through the Wagtail Docs and found this page (http://docs.wagtail.io/en/v2.1.1/advanced_topics/third_party_tutorials.html) and on that page was an article about dynamic templating. This is the page that has it: https://www.coactivate.org/projects/ejucovy/blog/2014/05/10/wagtail-notes-dynamic-templates-per-page/
The idea is to set a CharField and let the user select their template. In the following example they're using a drop down, which might even be better for you.
class CustomPage(Page):
template_string = models.CharField(max_length=255, choices=(
(”myapp/default.html”, “Default Template”),
(”myapp/three_column.html”, “Three Column Template”,
(”myapp/minimal.html”, “Minimal Template”)))
#property
def template(self):
return self.template_string
^ code is from the coactivate.org website, it's not mine to take credit for.
In the template property, you could check if not self.template_string: and set your default path in there.
Edit #1:
Adding Page inheritance.
You can add a parent Page (the Base class) and modify that, then extend any other class with your new Base class. Here's an example:
class BasePage(Page):
"""This is your base Page class. It inherits from Page, and children can extend from this."""
template_string = models.CharField(max_length=255, choices=(
(”myapp/default.html”, “Default Template”),
(”myapp/three_column.html”, “Three Column Template”,
(”myapp/minimal.html”, “Minimal Template”)))
#property
def template(self):
return self.template_string
class CustomPage(BasePage):
"""Your new custom Page."""
#property
def template(self):
"""Overwrite this property."""
return self.template_string
Additionally, you could set the BasePage to be an abstract class so your migrations don't create a database table for BasePage (if it's only used for inheritance)
Hard facts:
I am using Django 2.0 with python 3.6, if it makes any difference.
What I am trying to achieve is a link to a list of objects that belong to a summary.
I have a ManyToOne relationship in my models.py.
class Summary(models.model):
type=models.CharField
class Object(models.Model):
summary= models.ForeignKey(Summary, on_delete=models.CASCADE)
in urls.py
object_list= views.ObjectListViewSet.as_view({
'get': 'list'
})
urlpatterns = format_suffix_patterns([
url(r'^summary/(?P<pk>[^/.]+)/objects/$', object_list, name='summary-objects')
])
and now the idea was to give a user the possibility to click the an url in the browsable API and getting all objects.
So, I tried to write a MethodField in serializers.py. I am not able to get any reasonable URL here, the only solution would be to hardcode it.
class SummarySerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name="app:summary-detail")
objects= serializers.SerializerMethodField('get_obj_url')
def get_obj_url(self, obj):
pass
class Meta:
model = Summary
Is this possible?
Is it necessary to write a MethodField?
If yes, how do I get the url I need?
Actually, reverse, as suggested in the comments, does the trick.
The solution is:
def get_obj_url(self, obj):
request = self.context.get('request')
return request.build_absolute_uri(reverse('api-root')) + 'summary/{id}/objects'.format(
id=obj.id)
EDIT:Typo
I am performing a basic Django ModelForm create/validate/save operation. My custom clean methods are not being called when is_valid() is being called when running the code under the Eclipse debugger and I set a breakpoint after the form creation and the call to is_valid().
I have traced through the Django base code numerous times and it appears that the error dictionary on the ModelForm class is never set to None, which triggers the validation. I suspect that this is due to an interaction with the debugger accessing the _errors attribute of the ModelForm to display in the variables pane.
When I remove all breakpoints and let the code flow naturally, I can prove that the custom clean code is running by issuing print statements.
Is this a flaw in the Django ModelForm design, an Eclipse problem or am I barking up the wrong tree?
models.py:
from django.db import models
class TestModel1(models.Model):
field1 = models.CharField(max_length=45)
field2 = models.IntegerField(default=2)
field3 = models.CharField(max_length=45, null=True, blank=True)
forms.py:
from order.models import TestModel1
from django.forms import ModelForm
class OrderTestForm(ModelForm):
def clean_field1(self):
return self.cleaned_data['field1']
def clean_field2(self):
return self.cleaned_data['field2']
class Meta:
model = TestModel1
My test harness:
from forms import OrderTestForm
row = {'field1': 'test value', 'field2': '4', }
ff = OrderTestForm(row)
#ff.full_clean()
if ff.is_valid():
ff.save()
else:
print ff.errors
I have found the "answer" which is sort of a non-answer. The exact use case was receiving a CSV file from a customer. After inspection of the customer's actual data file, the data fields were padded with spaces -- many spaces. I trimmed the input and shoved that trimmed dictionary into the form and everything worked. Still does not explain why eclipse choked on this.
I had the same problem and tried to dig a little deeper and debug the framework.
There's probably a difference between regular forms and model forms which causes this not to work, but this hack (overriding is_valid() instead of clean(...)) worked for me:
def is_valid(self):
#run whatever ModelForm validations you need
return super(OrderTestForm, self).is_valid()
What if you try:
from order.models import TestModel1
from django.forms import ModelForm
class OrderTestForm(ModelForm):
class Meta:
model = TestModel1
def clean_field1(self):
value = self.cleaned_data['field1']
print value
return value
def clean_field2(self):
value = self.cleaned_data['field2']
print value
return value