I have multiple related tables defined in my Django models:
# first models.py
from django.db import models
class Character(models.Model):
first_field = models.DateTimeField()
second_field = models.TextField()
# second models.py
from django.db import models
class Op(models.Model):
fk_character = models.ForeignKey('Character')
some_field = models.DateTimeField()
other_field = models.TextField()
class Participant(models.Model):
fk_op = models.ForeignKey('Op')
fk_character = models.ForeignKey('Character')
some_other_field = models.IntegerField(default=0)
For now, I'm sending this data from a view to template in a way like this:
# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from second.models import MainModel
def home(request):
data = Op.objects.filter(some_field__isnull=True).order_by('-date')
rc = RequestContext(request, {'data':data})
return render_to_response('index.html', rc)
In this way I do have all the Op related data I need in my index.html template, but I'm struggling with logic to display this data in my template in a specific way. For example:
display a list of all Ops,
for each list item, check if Character is also a Participant in current Op item,
if it isn't, display some button, if it is than don't display the button
I know that template shouldn't handle any programming logic, but I'm also not sure what would be the best approach to solve this. Should I do all the logic in my view and construct a new object and send that object to my view or is there an easy way to solve this in template with current object I'm sending?
Update your model:
class Op(models.Model):
fk_character = models.ForeignKey('Character')
some_field = models.DateTimeField()
other_field = models.TextField()
def check_if_participant(self):
return bool(self.participant_set.all())
Display list of all Ops:
{% for op in data %}
{{op.some_field}}
{% if op.check_if_participant %}Yes - Character is participant {% endif %}
{% endfor %}
Related
Hi I am working with Django and I am trying to make a little system to register people and teams.
So far I can create teams and people in the admin site.
Now, I want to make a public form, where i.e. a trainer can register his team.
The Team has a foreignkey to Bundesland (the state).
I want a dropdown list that shows the states, I already made in the admin site. And then chose from it in the form. My "python crash course"-book doesn't cover this, so please help me. The answers I found so far in the documentation and on stackoverflow didn't work for me.
models.py:
from django.db import models
class Bundesland(models.Model):
bdl_kurz = models.CharField(max_length=2) #abbreviation
bdl_lang = models.CharField(max_length=25) #full name
--snip--
class Team(models.Model):
bdl = models.ForeignKey(Bundesland)
name = models.CharField(max_length=40)
plz = models.CharField(max_length=5)
ort = models.CharField(max_length=40)
strasse = models.CharField(max_length=40)
strnr = models.CharField(max_length=5)
telefon = models.CharField(max_length=20)
email = models.EmailField()
--snip--
forms.py:
from django import forms
from .models import Team
class TeamForm(forms.ModelForm):
class Meta:
model = Team
bdl = forms.ModelChoiceField(queryset='bdl_lang.objects.all()), empty_label=None)
fields = ['name', 'plz', 'ort', 'strasse', 'strnr', 'telefon', 'email']
labels = {'plz': 'PLZ', 'ort': 'Ort', 'strasse': 'Straße', 'strnr': 'Hausnr.', 'telefon': 'Telefon', 'email': 'Email'}
new_team.html:
<p>New Team</p>
<form action="{% url 'teilnehmer:new_team' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Submit data</button>
</form>
views.py: (if important)
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Bundesland, Gewichtsklasse, Team, Kaempfer
from .forms import TeamForm
--snip--
def new_team(request):
"""Add a new team."""
if request.method != 'POST':
# No data submitted; create a blank form
form = TeamForm()
else:
# POST data submitted; process data.
form = TeamForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('teilnehmer:index'))
context = {'form': form}
return render(request, 'teilnehmer/new_team.html', context)
So I can pick out a number of problems in your code.
bdl = forms.ModelChoiceField(queryset='bdl_lang.objects.all()), empty_label=None) - you do not need the starting quote right after the equal sign.
bdl_lang is a CharField so bdl_lang.objects.all() doesn't make sense. The queryset is an order dict of Django objects (defined via a model class). Replace this with bdl.objects.all(). From here, insert a __unicode__(self) method in your class Bundesland. This method should return the name you want in your choices. From looking at your code, it seems like you would want to return bdl_lang.
You need to include bdl in your fields option.
I hope this helps!
I have an application called "school" inside one of my django projects.
Below is the code of models.py
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=255)
birthday = models.DateField(blank=True)
class Class(models.Model):
name = models.CharField(max_length=255)
student = models.ForeignKey(Student,related_name='classes',null=True)
def __str__(self):
return self.name
And now, views.py:
from django.shortcuts import render
from .models import *
def test(request):
obj2 = Student.objects.get(name='john')
return render(request,'test/list.html', {'obj2':obj2} )
And finally, my template looks like this:
{% block content %}
<h2>
{{ obj2.classes }}
</h2>
{% endblock %}
In my template, I am using obj2.classes (i.e., responseobject.related_name). I want it to print the class name.
However when I access the site at http://127.0.0.1:8000/shop/ ,
it gives me this output:
shop.Class.None
How will I get the output as only "Class", that is the class name?
Would obj2._meta.get_field('classes').related_model.__name__ do the job? This will work on your view only, not on the template.
def test(request):
obj2 = Student.objects.get(name='john')
classes_name = obj2._meta.get_field('classes').related_model.__name__
return render(request, 'test/list.html',
{'obj2':obj2, 'classes_name': classes_name})
Using this method, you avoid to use obj2.classes, which hits the database to retrieve the object.
You can also get the verbose_name with obj2._meta.get_field('classes').related_model._meta.verbose_name.
UPDATE #2
Status: Still not solved
Updated: Thurs. Dec. 18, 11:30 a.m.
I'm currently using FullArticle.objects.order_by('?').first() to get a random article from my database, but it's not working. There is probably something missing from my models, view or url.py that's missing.
models.py
from django.db import models
from django.core.urlresolvers import reverse
# Create your models here.
class FullArticleQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
class FullArticle(models.Model):
title = models.CharField(max_length=150)
author = models.CharField(max_length=150)
slug = models.SlugField(max_length=200, unique=True)
pubDate = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
category = models.CharField(max_length=150)
heroImage = models.CharField(max_length=250, blank=True)
relatedImage = models.CharField(max_length=250, blank=True)
body = models.TextField()
publish = models.BooleanField(default=True)
gameRank = models.CharField(max_length=150, blank=True, null=True)
objects = FullArticleQuerySet.as_manager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("FullArticle_detailed", kwargs={"slug": self.slug})
class Meta:
verbose_name = "Blog entry"
verbose_name_plural = "Blog Entries"
ordering = ["-pubDate"]
views.py
from django.views import generic
from . import models
from .models import FullArticle
# Create your views here.
class BlogIndex(generic.ListView):
queryset = models.FullArticle.objects.published()
template_name = "list.html"
randomArticle = FullArticle.objects.order_by('?').first()
class BlogDetail(generic.DetailView):
model = models.FullArticle
template_name = "detailed.html"
urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^$', views.BlogIndex.as_view(), name="list"),
url(r'^(?P<slug>\S+)', views.BlogDetail.as_view(), name="detailed"),
)
Section in list.html that I want to be random
<div class="mainContent clearfix">
<div class="wrapper">
<h1>Top 10 Video Games</h1>
{% for article in object_list|slice:":1" %}
<p class="date">{{article.pubDate|date:"l, F j, Y" }}</p> | <p class="author">{{article.author}}</p>
<img src="{{article.heroImage}}" alt="" class="mediumImage">
<p class="caption">{{article.body|truncatewords:"80"}}</p>
{% endfor %}
I assume that FullArticle.objects.order_by('?')[0] will give me a
random item from my class of FullArticle. But, let's say that out of
my model, I only want data associated with the specific parts of the
article: title, author, heroImage and body. How would I go about doing
that?
To get specific fields of an object, use values or values_list. The first will return dictionaries, the second tuples:
FullArticle.objects.order_by('?').values('title','author','heroImage','body').first()
The above would result in something like:
{'title': 'Foo', 'author': 'Foo Author', ... }
I've also tacked on your suggestion of random =
FullArticle.objects.order_by('?')[0] called it "random" instead.
Not sure what this is about, but try to avoid shadowing built-in libraries, like random.
1) Actually you almost did it.
try:
article = FullArticle.objects.order_by('?')[0]
except IndexError:
article = None
2) You could use this in models.py as well as in views.py. IMHO there is no need to extract this string to separate method so I would write this code wherever I need it.
3) Better use ORM don't convert db result to list to choose first item. This is can be really memory and CPU expensive.
Getting a random article would usually be done in a view, or as a modelmanager method, or as a class method. Fullarticle.random should not be a class attribute. That will not work as you expect.
# Used in a view.
article = FullArticle.objects.order_by('?').first()
# you can also make a random() method in your model manager.
def random(self):
return self.get_queryset().order_by('?').first()
# or as a class method inside FullArticle
#classmethod
def random(cls):
return cls.objects.order_by('?').first()
I'm not quite sure what exactly you mean by this.
I only want data associated with the specific parts of the article: title, author, heroImage and body. How would I go about doing that?
To access specific attributes you do this:
title = article.title
author = article.author
If you don't need to use article.category, just don't access it.
from django.views.generic import DetailView
from books.models import Publisher, Book
To pass data from your (class based) View to the template it has to be added to the context.
Here's an example from the official documentation:
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
source: https://docs.djangoproject.com/en/1.7/topics/class-based-views/generic-display/#adding-extra-context
Lots of people find Class Based Views in Django to be a bit confusing. I would recommend that you understand how function based views work before you start doing anything complicated with CBVs.
I have the below models for which I'm trying to create a form for:
class Letter(models.Model):
title = models.CharField(max_length=100)
publish_date = models.TimeField()
class LetterRecipients(models.Model):
letter = models.ForeignKey(Letter)
recipient_name = models.CharField(max_length=200)
recipient_rating = models.IntegerField()
has_responded = models.BooleanField()
I'd like a single form that allows the user to enter a title and publish_date for the letter, and in the same form enter multiple recipients by name and rating.
Can anyone help with creating the form model for this? I can't figure out how to have django generate this form using {{ form.as_p }}. I think I'll have to use jQuery to create the additional recipient rows on the HTML page, but how would I get django to parse those into the model?
Any help would be greatly appreciated.
Thanks.
Ark
Ark, you can use ModelMultipleChoiceField in Django form. Here are some roughly example. I create "posts" apps just for quick testing :
forms.py
from django import forms
from django_test.posts.models import Letter, LetterRecipients
class LetterForm(forms.Form):
title = forms.CharField()
publish_date = forms.TimeField()
recepient = forms.ModelMultipleChoiceField(
queryset=LetterRecipients.objects.all()
)
models.py
from django.db import models
class Letter(models.Model):
title = models.CharField(max_length=100)
publish_date = models.TimeField()
class LetterRecipients(models.Model):
letter = models.ForeignKey(Letter)
recipient_name = models.CharField(max_length=200)
recipient_rating = models.IntegerField()
has_responded = models.BooleanField()
def __unicode__(self):
return self.recipient_name
views.py
# Create your views here.
from django_test.posts.forms import LetterForm
from django.shortcuts import render
def index(request):
form = LetterForm()
data = {'form': form}
return render(request, 'posts/index.html', data)
index.html
{% load url from future %}
{{ form.as_p }}
I'm rather new to Django, so please forgive the rather newbish question I need to ask. Basically, I have a problem I'm having great difficulty implementing after countless searches.
What I would like to do, is create an input form in a page, and populate it with data from the database. I would then like to be able to click on a button to update whatever changes I make to the form. The catch here is that the form will take data from two models, a main model, and a submodel related to it. Exactly like how an Invoice might have multiple items within it.
The furthest I've gotten was displaying the main model but not the submodel, or displaying everything, but the button not doing anything. Here are the code:
models.py
import datetime
from django.db import models
from django.utils import timezone
class InvoiceList(models.Model):
invoice_number = models.IntegerField(default=0)
recipient = models.CharField(max_length=100)
issue_date = models.DateField()
deadline = models.DateField()
additional_info = models.CharField(max_length=500)
def __str__(self):
return self.recipient
class InvoiceItem(models.Model):
item_description = models.CharField(max_length=150)
number = models.IntegerField(default=1)
price = models.IntegerField(default=0)
tax = models.IntegerField(default=0)
list = models.ForeignKey(InvoiceList)
def __str__(self):
return self.item_description + " (" + str(self.list) + ")"
forms.py (EDITED) (added "can_delete+=False" to prevent appearance of "Delete" checkbox. Checkbox needs to be checked in order for "is_valid" to flag as True... which is nonsense. So remove that!)
import datetime
from bill.models import *
from django.utils import timezone
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
class InvoiceListForm(ModelForm):
class Meta:
model = InvoiceList
fields = ['invoice_number', 'recipient', 'issue_date', 'deadline', 'additional_info']
class InvoiceItemForm(ModelForm):
class Meta:
model = InvoiceItem
exclude = ('list',)
fields = ['item_description', 'number', 'price', 'tax']
InvoiceFormSet = inlineformset_factory(InvoiceList, InvoiceItem, fields=('id','item_description','number','price','tax',), extra=0, can_delete=False)
Partial view of views.py (EDITED) (Probably can be cleaned heavily, but here's the engine to make it update!)
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404, render
from django.utils import timezone
from django.core.context_processors import csrf
from django.forms.formsets import formset_factory, BaseFormSet
from django.forms.models import modelformset_factory
from bill.forms import *
from .forms import InvoiceFormSet
from django.views.generic.edit import UpdateView
from django.forms import inlineformset_factory
from django.template import RequestContext
def update_edit(request, invoice_id):
a = get_object_or_404(InvoiceList, pk=invoice_id)
b = InvoiceFormSet(instance=a, prefix="item")
c = InvoiceListForm(instance=a, prefix="list")
if request.method == 'POST':
gaga = InvoiceListForm(request.POST, instance=a, prefix="list")
lala = InvoiceFormSet(request.POST, instance=a, prefix="items")
if gaga.is_valid() and lala.is_valid():
gaga.save()
lala.save()
return HttpResponse('Good, saved the thing!')
else:
return HttpResponse('No shway! Didn't save cos not valid!')
else:
c = InvoiceListForm(instance=a, prefix="list")
b = InvoiceFormSet(instance=a, prefix="items")
d = {'invoice_info': c, 'items': b}
d.update(csrf(request))
return render(request, 'bill/update.html', {'form': invoice_info, 'items': invoice_stuff})
Here's the frontend update.html (EDITED) (Added management thing)
<h1>Updating Invoice</h1>
<form action="." name="stock_details" method="post">
{% csrf_token %}
<hr>
{{ form.as_p }}
{{ items.management_form }}
{% for item in items %}
{{ item }}
{% endfor %}
<hr>
<input type='submit' value='Update'/>
</form>
I would put in {{ item.as_p }}, but that doesn't display anything unfortunately. I'm not sure why. The above displays all of the data. The exception are the items, they don't appear inside an input tag... I'll have to do that manually I suppose.
EDIT - I've modified the code to show both the invoice and its child items into the formset, which displays well and has content populated. I'm trying to figure out how to save the form at this point, assuming there are changes. Help?
All solved! Thank you very much!