I am makine business directory and i stucked in city and districts pages of business directory.
I made a simple business directory. All i want three queries;
Forexample category name: Manufacturing
First: I want one page like this: abc.com/directory/category/slug:slug(this slug means category name)/ ( I did, i have no problem with this page.
Second: City url like this abc.com/directory/category/slug:slug/(city name with slug style)/. forexample abc.com/category/manufacturing/london/
Third: District url like this abc.com/directory/category/slug:slug/(city name with slug style)/. forexample abc.com/category/manufacturing/london/southwark(district names)
I only did first one and second and third made me crazy...
I tried lots of things but failed...
Here are my codes:
models.py
from django.db import models
from django.urls import reverse
from tinymce import models as tinymce_models
# Create your models here.
class City(models.Model):
city = models.CharField(max_length=50)
slug = models.SlugField()
def __str__(self):
return str(self.city)
class District(models.Model):
district = models.CharField(max_length=50)
slug = models.SlugField()
city = models.ForeignKey(City, on_delete=models.CASCADE)
def __str__(self):
return str(self.district)
class FirmaCategory(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
class Meta:
verbose_name_plural = 'Firma Kategorileri'
def __str__(self):
return str(self.title)
class Firma(models.Model):
category = models.ForeignKey(FirmaCategory, related_name="Firma", on_delete=models.CASCADE)
title = models.CharField(max_length=255)
slug = models.SlugField()
adres = tinymce_models.HTMLField()
tel = tinymce_models.HTMLField()
website = tinymce_models.HTMLField()
email = tinymce_models.HTMLField()
intro = tinymce_models.HTMLField()
body = tinymce_models.HTMLField()
city = models.ForeignKey(City,related_name="FirmaCategory" ,on_delete=models.CASCADE)
district = models.ForeignKey(District,related_name="FirmaCategory", on_delete=models.CASCADE)
#url = models.CharField(max_length=255)
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Firmalar'
def __str__(self):
return str(self.title)
def get_absolute_url(self):
return reverse('firma-frontpage')
views.py
from django.db.models import Q
from django.shortcuts import render
from .models import Firma, FirmaCategory, City, District
from django.utils.html import format_html
from django.views.generic import CreateView
from .forms import FirmaForm
# Create your views here.
def firmaana(request):
firmalar = Firma.objects.all()
context = {
'firmalar': firmalar
}
return render(request, 'firma/firma-frontpage.html', context)
def firmadetail(request, slug):
firmax = Firma.objects.get(slug=slug)
context = {
'firmax': firmax,
}
return render(request, 'firma/firma-detail.html', context)
def firmacategory(request, slug):
firmacategory = FirmaCategory.objects.get(slug=slug)
context = {
'firmacategory': firmacategory
}
return render(request, 'firma/firma-category.html', context)
urls. py
urlpatterns = [
path('kategory/city/<city>/', views.list_businesses_by_city, name='firmail'),
path("", views.firmaana, name="firma-frontpage"),
path("<slug:slug>/", views.firmadetail, name="firma-detail"),
path("kategory/<slug:slug>/", views.firmacategory, name="firma-category"),
path("1/add-firma/", FirmaEkle.as_view(), name="firma-ekle"),
path('tinymce/', include('tinymce.urls')),
If i understood you correctly...
views.py
def firmacity(request, city_slug):
try:
city = City.objects.get(slug=city_slug)
context = {
"firma" : Firma.objects.filter (city=city)
}
return render(request, tmpl, context)
except City.DoesNotExist:
context = {
"error" : "City does not exist"
}
return render(request, tmpl, context)
def firmadistrict(request, city_slug, dist_slug):
city = City.objects.get(slug=city_slug)
if city is not None:
district = District.obects.get(city=city)
if district is not None:
firma = Firma.objects.filter(district=district)
context = {
"firma" :firma,
}
return render(request, tmpl, context)
context = {
"error" : "Error in city/district"
}
return render(request, tmpl, context)
There are two different approaches for dealing with errors such as someone intentionally entering other values in browser url. Hope it helps.
I will edit here your second question. So if i understood you correctly. You want to retrieve companies data by categories. So that you can access fields (city, district) of that company in exact company category.
views.py
def firmabycategory(request, cat_slug):
try:
category = FirmaCategory.objects.get(slug=cat_slug)
companies = Firma.objects.filter(category=category)
context = {
'companies': companies,
}
return render(request, tmpl, context)
except FirmaCategory.DoesNotExist:
context = {
'error': 'Selected Category does not exist!',
}
return render(request, tmpl, context)
template(html):
{% for company in companies %}
name: {{ company.title }}
category: {{ company.category }}
city: {{ company.city }}
district: {{ company.district }}
{% endfor %}
Related
I'm trying to test redirect from a form using POST. I'm following the mdn web doc tutorial for Django and thought I would see if I could do some of my own test which are not in the tutorial. I'm try to test the book creation form in the tutorial to see if it redirects to book details page which it should do automatically because it's a class based generic view. It works correctly when I test locally but I cannot get the testcase to pass. Thanks for the help in advance.
This is the error:
> =====================================================================
FAIL: test_redirects_to_book_details_on_success (catalog.tests.test_views.BookCreateView)
> ----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\makor\mypythonscripts\django_projects\locallibrary\catalog\tests\test_views.py", line 399, in test_redirects_to_book_details_on_success
self.assertRedirects(response, reverse('book-detail', kwargs={'pk': 1}))
File "C:\Users\makor\mypythonscripts\django_projects\venv\lib\site-packages\django\test\testcases.py", line 512, in assertRedirects
self.assertEqual(
AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)
----------------------------------------------------------------------
Ran 1 test in 0.341s
FAILED (failures=1)
Destroying test database for alias 'default'...
models.py
from django.db import models
from django.urls import reverse # Used to generate URLs by reversing the URL pattern.
from django.contrib.auth.models import User
from datetime import date
import uuid # Required for unique book instances
class Genre(models.Model):
"""Model representing book genre."""
name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
def __str__(self):
"""String representation of Model object."""
return self.name
class Language(models.Model):
"""Model representing a langauge."""
LANGUAGES = (
('English', 'English'),
('French', 'French'),
('German', 'German'),
('Spanish', 'Spanish'),
)
language = models.CharField(max_length=20, choices=LANGUAGES, blank=False, default='English', help_text='Availble languages')
def __str__(self):
"""String representation of Model object."""
return self.language
class Book(models.Model):
"""Model representing a book (but not a specific copy of a book)."""
title = models.CharField(max_length=200)
# Foreign Key used because book can only have one author, but author can have multiply books.
author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book.')
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 character ISBN number')
# ManyToManyField used because genre can contain many books. Books can cover many genres.
# Genre class has already been defined, so we can specify the object above.
genre = models.ManyToManyField('Genre', help_text='Select a genre for this book.')
language = models.ManyToManyField('Language', help_text='Select the langauge.')
def __str__(self):
"""String for representing the Model object."""
return self.title
def get_absolute_url(self):
"""Returns the URL to access a detail record for this book."""
return reverse('book-detail', args=[str(self.id)])
def display_genre(self):
"""Create a string for the Genre. This is required to display genre in Admin."""
return ', '.join(genre.name for genre in self.genre.all()[:3])
display_genre.short_description = 'Genre'
class BookInstance(models.Model):
"""Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
help_text='Unique ID for this particular book across the whole library.')
book = models.ForeignKey('Book', on_delete=models.RESTRICT, null=True)
imprint = models.CharField(max_length=200, blank=True)
due_back = models.DateField(null=True, blank=True)
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
LOAN_STATUS = (
('m', 'Maintenance'),
('o', 'On loan'),
('a', 'Available'),
('r', 'Reserved'),
)
status = models.CharField(
max_length=1,
choices=LOAN_STATUS,
blank=True,
default='m',
help_text='Book availability',
)
class Meta:
ordering = ['due_back']
permissions = (('can_mark_returned', 'set book as returned'),)
def __str__(self):
"""String representing the Model object."""
return f'{self.id} ({self.book.title})'
#property
def is_overdue(self):
"""Determines if the book is overdue based on due date and current date."""
return bool(self.due_back and date.today() > self.due_back)
class Author(models.Model):
"""Model representing an author."""
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField(null=True, blank=True)
date_of_death = models.DateField('died', null=True, blank=True)
class Meta:
ordering = ['last_name', 'first_name']
def get_absolute_url(self):
"""Returns the URL to access a particular author instance."""
return reverse('author-detail', args=[str(self.id)])
def __str__(self):
"""String representing the Model object."""
return f'{self.last_name}, {self.first_name}'
views.py
import datetime
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse, reverse_lazy
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.decorators import login_required, permission_required
from . models import Book, Author, BookInstance, Genre, Language
from . forms import RenewBookForm
def index(request):
"""View function for home page of site."""
# Generate counts of some main objects.
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
# The 'all()' is implied by default.
num_authors = Author.objects.count()
# Number of visits to this view, as counted in the session variable.
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
# Generate counts for genre.
num_genre = Genre.objects.all().count()
# Filter books containing a particular word.
title = 'game of thrones'
num_title = Book.objects.filter(title__contains=title.lower()).count()
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
'num_genre': num_genre,
'num_title': num_title,
'num_visits': num_visits,
}
# Render the HTML template index.html with the data in the context variable.
return render(request, 'index.html', context=context)
class BookListView(generic.ListView):
model = Book
paginate_by = 10
class BookDetailView(generic.DetailView):
model = Book
class AuthorListView(generic.ListView):
model = Author
paginate_by = 10
class AuthorDetailView(generic.DetailView):
model = Author
class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView):
"""Generic class-based view listing books on loan to current user."""
model = BookInstance
template_name = 'catalog/bookinstance_list_borrowed_user.html'
paginate_by = 10
def get_queryset(self):
return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')
class BorrowedListView(PermissionRequiredMixin, generic.ListView):
"""Generic class-based view listing all books, requires correct permissions."""
permission_required = 'catalog.can_mark_returned'
model = BookInstance
template_name = 'catalog/borrowed_list.html'
paginate_by = 10
def get_queryset(self):
return BookInstance.objects.filter(status__exact='o').order_by('due_back')
#login_required
#permission_required('catalog.can_mark_returned', raise_exception=True)
def renew_book_librarian(request, pk):
book_instance = get_object_or_404(BookInstance, pk=pk)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = RenewBookForm(request.POST)
# Check if the form is valid
if form.is_valid():
# Process the data in form.cleaned_data as required (here we just write it to the model due_back field)
book_instance.due_back = form.cleaned_data['renewal_date']
book_instance.save()
# Redirect to a new URL:
return HttpResponseRedirect(reverse('all-borrowed'))
else:
context = {
'form': form,
'book_instance': book_instance,
}
return render(request, 'catalog/book_renew_librarian.html', context)
# If this is a GET (or any other method) create the default form.
else:
proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
form = RenewBookForm(initial={'renewal_date': proposed_renewal_date})
context = {
'form': form,
'book_instance': book_instance,
}
return render(request, 'catalog/book_renew_librarian.html', context)
class AuthorCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'catalog.can_mark_returned'
model = Author
fields = ['first_name', 'last_name', 'date_of_birth', 'date_of_death']
initial = {'date_of_death': '11/06/2022'}
class AuthorUpdate(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
permission_required = 'catalog.can_mark_returned'
model = Author
fields = '__all__' # Not recommended (potential security issue if more fields are added.)
class AuthorDelete(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
permission_required = 'catalog.can_mark_returned'
model = Author
success_url = reverse_lazy('authors')
class BookCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'catalog.can_mark_returned'
model = Book
fields = ['title', 'author', 'summary', 'isbn', 'genre', 'language']
class BookUpdate(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
permission_required = 'catalog.can_mark_returned'
model = Book
fields = '__all__'
class BookDelete(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
permission_required = 'catalog.can_mark_returned'
model = Book
success_url = reverse_lazy('books')
test.py
class BookCreateView(TestCase):
def setUp(self):
# Create a user
test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK')
test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD')
test_user1.save()
test_user2.save()
# Give test_user2 permission to create Book.
permission = Permission.objects.get(name='set book as returned')
test_user2.user_permissions.add(permission)
test_user2.save()
test_author = Author.objects.create(first_name='John', last_name='Smith')
test_genre = Genre.objects.create(name='Fantasy')
test_language = Language.objects.create(language='English')
test_author.save()
test_genre.save()
test_language.save()
self.author = Author.objects.get(id=1)
self.genre = Genre.objects.get(id=1)
self.language = Language.objects.get(id=1)
def test_redirect_if_not_logged_in(self):
response = self.client.get(reverse('book-create'))
# Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable)
self.assertEqual(response.status_code, 302)
self.assertTrue(response.url.startswith('/accounts/login/'))
def test_forbidden_if_logged_in_but_not_correct_permission(self):
login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK')
response = self.client.get(reverse('book-create'))
self.assertEqual(response.status_code, 403)
def test_logged_in_with_permission_to_create_book(self):
login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD')
response = self.client.get(reverse('book-create'))
# Check that it lets us login - this is our book and we have the right permissions.
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD')
response = self.client.get(reverse('book-create'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'catalog/book_form.html')
def test_redirects_to_book_details_on_success(self):
login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD')
response = self.client.post(reverse('book-create'), {'title': 'Test',
'author': self.author,
'summary': 'It\'s all good',
'isbn': '1234567',
'genre': self.genre,
'language': self.language,
})
self.assertRedirects(response, reverse('book-detail', kwargs={'pk': 1}))
form template
{% extends 'base_generic.html' %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit" />
</form>
{% endblock %}
Screenshot of form
I have been at this for about two days but I think my beginners luck has ran out. I can usually figure it out by myself after a while but not anymore as this is my first post. I think the data i am entering into the client.post is not working and giving the correct response object. Sorry if my lingo is not correct as I am new to all this.
I posted a screenshot below to hopefully make this easier to understand so I will reference it in my question.
I am trying to create a recipe cost calculator app. I have 3 model namely Recipe, RecipeIngredient and Ingredient
The user will add ingredients to the database and then create recipes using those ingredients throught the RecipeIngredient model.
When creating an Ingredient the user selects a unit eg. (grams). Now when the user goes to create a Recipe (see screenshot below) I want to only display the units that are relevant to that ingredient and not all of them for eg. A user added Beef and the unit was grams now when the user is adding a RecipeIngredient to the Recipe I want them to only be able to select from the "Weight" category in the example (see screenshot below). The reason for this is because grams can't be converted to milliliters and so it shouldn't even be a choice.
If anything is unclear or you need more information just let me know.
Models
Recipe Models
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
from ingredients.models import Ingredient
class Recipe(models.Model):
"""Store recipe information and costs"""
class Meta:
"""Meta definition for Recipe."""
verbose_name = "Recipe"
verbose_name_plural = "Recipes"
ordering = ("name",)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
name = models.CharField(max_length=155)
yield_count = models.PositiveIntegerField()
yield_units = models.CharField(max_length=155, default="servings")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("recipe:detail", kwargs={"id": self.pk})
def get_update_url(self):
return reverse("recipe:update", kwargs={"id": self.pk})
class RecipeIngredient(models.Model):
"""Holds more information about how much of a certain ingredient is used inside a recipe"""
class Meta:
"""Meta definition for RecipeIngredient"""
verbose_name = "RecipeIngredient"
verbose_name_plural = "RecipeIngredients"
# NOTE: User should first choose the ingredient
recipe = models.ForeignKey(Recipe, related_name="ingredients", on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, related_name="ingredient", on_delete=models.CASCADE)
# NOTE: Then the amount an unit should be asked based on that
amount = models.DecimalField(max_digits=20, decimal_places=2)
unit = models.CharField(max_length=10, choices=Ingredient.UNIT_CHOICES, default=None)
def __str__(self):
"""Unicode representation of RecipeIngredient"""
return self.ingredient.__str__()
Ingredient Model
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
from pint import UnitRegistry
from .choices import ALL_UNIT_CHOICES
class Ingredient(models.Model):
"""Stores data about an ingredient to be used by a Recipe model."""
class Meta:
"""Meta definition for Ingredient."""
verbose_name = "Ingredient"
verbose_name_plural = "Ingredients"
ordering = ("name",)
# Unit choices that will display in a dropdown
# It will be ordered by group (eg. Weight, Volume)
UNIT_CHOICES = ALL_UNIT_CHOICES
ureg = UnitRegistry()
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
name = models.CharField(max_length=50, unique=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
size = models.DecimalField(max_digits=10, decimal_places=2)
unit = models.CharField(max_length=10, choices=UNIT_CHOICES, default=None)
def __str__(self):
"""Unicode representation of Ingredient."""
return self.name
def get_absolute_url(self):
"""Return absolute url for Ingredient"""
return reverse("ingredient:detail", kwargs={"id": self.pk})
def get_update_url(self):
"""Return the url for update page"""
return reverse("ingredient:update", kwargs={"id": self.pk})
def get_delete_url(self):
return reverse("ingredient:delete", kwargs={"id": self.pk})
def save(self, *args, **kwargs):
self.unit = self.ureg.Unit(self.unit)
super(Ingredient, self).save(*args, **kwargs)
Views
def create_recipe(request):
template_name = "recipes/create.html"
form = CreateRecipeForm(request.POST or None)
ingredient_choice_form = IngredientChoiceForm(request.POST or None, request=request)
Formset = modelformset_factory(RecipeIngredient, form=CreateRecipeIngredientForm, extra=0)
formset = Formset(request.POST or None, queryset=Recipe.objects.none())
context = {
"form": form,
"ingredient_choice_form": ingredient_choice_form,
"formset": formset,
}
print(request.POST)
return render(request, template_name, context)
# This is the view being calle by HTMX everytime an ingredient is selected
def get_recipe_ingredient_details(request):
template_name = "recipes/hx_snippets/add_recipe_ingredient_details.html"
ingredient_id = request.GET.get("ingredients")
if not ingredient_id:
return HttpResponse("")
ingredient = Ingredient.objects.get(id=ingredient_id)
choices = get_unit_group(ingredient.unit)
Formset = modelformset_factory(RecipeIngredient, form=CreateRecipeIngredientForm, extra=1)
formset = Formset(
request.POST or None,
queryset=RecipeIngredient.objects.none(),
initial=[
{
"ingredient": ingredient,
"unit": choices,
},
],
)
context = {
"formset": formset,
"ingredient": ingredient,
}
Templates
Template returned by HTMX request
<p>
{% for form in formset %}
{{ form }}
{% endfor %}
</p>
main create template
{% block content %}
<h1>Create Recipe</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<h3>Add ingredients</h3>
{{ formset.management_form }}
<div id="ingredient-form"></div>
{{ ingredient_choice_form.as_p }} <-- this is an HTMX get request that calls the get_recipe_ingredient_details view
<p><button type="submit">Create</button></p>
</form>
{% endblock content %}
{% block scripts %}
<script src="{% static 'js/recipes/addFormsetField.js' %}"></script>
{% endblock scripts %}
Choices.py
from django.db import models
class WeightUnitChoices(models.TextChoices):
GRAMS = "gram", "gram"
OZ = "ounce", "ounce"
LBS = "pound", "pound"
KG = "kilogram", "kilogram"
T = "tonne", "tonne"
class VolumeUnitChoices(models.TextChoices):
ML = "milliliter", "milliliter"
L = "liter", "liter"
TSP = "teaspoon", "teaspoon"
TBPS = "tablespoon", "tablespoon"
ALL_UNIT_CHOICES = [
(None, "Select Unit"),
("Weight", WeightUnitChoices.choices),
("Volume", VolumeUnitChoices.choices),
]
def get_unit_group(unit):
"""returns the unit group to which unit belongs to"""
match unit:
case unit if unit in dict(WeightUnitChoices.choices):
return WeightUnitChoices.choices
case unit if unit in dict(VolumeUnitChoices.choices):
return VolumeUnitChoices.choices
case _:
# Return all available units
return ALL_UNIT_CHOICES
Screenshot
I tried very hard to find out the problem, but I failed.
I am getting the following exception:
Error-NoneType object has no attribute 'membership_type'
I think that the problem is in context as if I use context as None then the error occurs.
I tried to use a foreign key to referring the Membership class and all the objects of it, but still get this error.
models.py
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
MEMBERSHIP_CHOICES = (
('Enterprise','ent'),
('Professional','pro'),
('Free','free')
)
class Membership(models.Model):
slug = models.SlugField()
membership_type =
models.CharField(choices=MEMBERSHIP_CHOICES,default='Free',max_length=30)
price = models.IntegerField(default=15)
stripe_plan_id = models.CharField(max_length=40)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user= models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=40)
membership = models.ForeignKey(Membership, on_delete=models.SET_NULL,
null=True)
def __str__(self):
return self.user.username
def post_save_usermembership_create(sender,instance, created, *args,
**kwargs):
if created:
UserMembership.objects.get_or_create(user= instance)
user_membership, created = UserMembership.objects.get_or_create(user=
instance)
if user_membership.stripe_customer_id is None or
user_membership.stripe_customer_id=='':
new_customer_id = stripe.Customer.create(email= instance.email)
user_membership.stripe_customer_id = new_customer_id['id']
user_membership.save()
post_save.connect(post_save_usermembership_create,
sender=settings.AUTH_USER_MODEL)
class Subscription(models.Model):
user_membership = models.ForeignKey(UserMembership,
on_delete=models.CASCADE)
stripe_subscription_id = models.CharField(max_length=40)
active = models.BooleanField(default=True)
def __str__(self):
return self.user_membership.user.username
courses/views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView,View
from .models import Course, Lesson
from membership_app.models import UserMembership
class CourseListView(ListView):
model = Course
class CourseDetailView(DetailView):
model = Course
class LessonDetailView(View):
def get(self, request, course_slug, lesson_slug, *args, **kwargs):
course_qs = Course.objects.filter(slug=course_slug)
if course_qs.exists():
course = course_qs.first()
lesson_qs = course.lessons.filter(slug=lesson_slug)
if lesson_qs.exists():
lesson = lesson_qs.first()
user_membership = UserMembership.objects.filter(user = request.user).first()
user_membership_type =
getattr(user_membership.membership,'membership_type',None)
# print(user_membership_type)
course_allowed_membership_type = course.allowed_membership.all()
context = {
'object': None
}
if course_allowed_membership_type.filter(membership_type=user_membership_type).exists():
context = {'object':lesson}
return render(request, "courses/lesson_detail.html",context)
templates
{% if object is not None %}
{{ object.title }}
{{ object.description }}
{% else %}
<h3>Upgrade Membership</h3>
{% endif %}
Your problem is in this line.
user_membership_type = user_membership.membership.membership_type
The reason is that you are allowing UserMembership.membership to be a null value. So when you retrieve a UserMembership with membership equal to None and then try to get membership_type off of that it raises an error. I think that getattr is your best solution to this problem.
user_membership_type = getattr(user_membership.membership, 'membership_type', None)
I want to retrieve the question_description answer_descritption and question_image answer_image if found in the database according to topic and question type using two ChoiceField for both: Topic and Question Type.
However, I don't know how to do that. I have seen some tutorials and gotten glimpses of what I have to do, but I am not sure how to preform the same techniques on my case because online there are not that many ChoiceField examples, except that there are general examples on how to use forms and extract data from the database.
This is the models.py
from django.db import models
from home.choices import *
# Create your models here.
class Topic(models.Model):
topic_name = models.IntegerField(
choices = question_topic_name_choices, default = 1)
def __str__(self):
return '%s' % self.topic_name
class Image (models.Model):
image_file = models.ImageField()
def __str__(self):
return '%s' % self.image_file
class Question(models.Model):
question_type = models. IntegerField(
choices = questions_type_choices, default = 1)
question_topic = models.ForeignKey( 'Topic',
on_delete=models.CASCADE,
blank=True,
null=True)
question_description = models.TextField()
question_answer = models.ForeignKey( 'Answer',
on_delete=models.CASCADE,
blank=True,
null=True)
question_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.question_type
class Answer(models.Model):
answer_description = models.TextField()
answer_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
answer_topic = models.ForeignKey( 'Topic',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.answer_description
This is the forms.py
from django import forms
from betterforms.multiform import MultiModelForm
from .models import Topic, Image, Question, Answer
from .choices import questions_type_choices, question_topic_name_choices
class TopicForm(forms.ModelForm):
topic_name = forms.ChoiceField(
choices=question_topic_name_choices,
widget = forms.Select(
attrs = {'class': 'home-select-one'}
))
class Meta:
model = Topic
fields = ['topic_name',]
def __str__(self):
return self.fields
class QuestionForm(forms.ModelForm):
question_type = forms.ChoiceField(
choices= questions_type_choices,
widget = forms.Select(
attrs = {'class': 'home-select-two'},
))
class Meta:
model = Question
fields = ['question_type',]
def __str__(self):
return self.fields
class QuizMultiForm(MultiModelForm):
form_classes = {
'topics':TopicForm,
'questions':QuestionForm
}
This is the views.py
from django.shortcuts import render, render_to_response
from django.views.generic import TemplateView
from home.models import Topic, Image, Question, Answer
from home.forms import QuizMultiForm
class QuizView(TemplateView):
template_name = 'index.html'
def get(self, request):
# What queries do I need to put here to get the question and answer's description according to the ChoiceField input
form = QuizMultiForm()
return render (request, self.template_name, {'form': form})
def post(self, request):
form = QuizMultiForm(request.POST)
if form.is_valid():
text = form.cleaned_data['topic_name', 'question_type'] # I don't know what to put here!
args = {'form': form, 'text': text}
return render (request, self.template_name, args)
This is the template:
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" id="home-Physics-time-button">It is Physics Time</button>
<h1> {{ text }} </h1>
</form>
{% endblock content %}
I would appropriate the help!
Thank you!
The cleaned_data attribute of the form, contains a dictionary that maps the name of the field with the bounded data. And from the MultiForm docs you can read:
cleaned_data
Returns an OrderedDict of the cleaned_data for each of the child forms.
Just extract data like this:
topic_name = form.cleaned_data['topics']['topic_name']
question_type = form.cleaned_data['question']['question_type']
# And so on ...
I'm confused about how to pull in related information from two different tables.
If I go to localhost:8000/user/username, it should display the users profile and user reviews below. because the username is being passed through the URL into the views function. Is that correct?
Also, is it required that I use foreign key to accomplish this? I've read the docs and I'm still not completely sure how a foreign key would help me accomplish my goal here.
Models
from django.db import models
class User(models.Model):
name = models.CharField(max_length=20)
reviewer = models.CharField(max_length=20)
password = models.TextField()
zipcode = models.Charfield(max_length=100)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
return self.name
class UserReview(models.Model):
name = models.ForeignKey(User)
author = models.CharField(max_length=50)
pub_date = models.DateField()
stars = models.IntegerField(max_length=5)
comment = models.CharField(max_length=100)
def __str__(self): # __unicode__ on Python 2
return self.name
Views
from django.shortcuts import render
def index(request):
profile_info = User.objects.filter(name=username)
context = {‘profile_info’: profile_info}
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
URLS
urlpatterns = patterns('',
url(r'^user/(?P<username>\w+)/', 'index'),
)
There's a couple things you need to do. The first is that you need to pass the parameter into the view function, and then you'll need to display the ratings in the template.
#view
def index(request, username):
profile_info = User.objects.filter(name=username)
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
# randomtemplate.html
{{ username }}
{{ latest_reviews }}