Unable to connect model to user in django - django

So i have a model called folder, i want to show all the folder created by current user on HomeView, but somehow it's not working, what i think is that folders are not getting connected to user who created them.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.deletion import CASCADE
from django.core.validators import MinValueValidator
from django.core.exceptions import PermissionDenied
# The Folders Model.
class Folder(models.Model):
name = models.CharField(max_length = 250)
parent = models.ForeignKey('self', on_delete = CASCADE, null = True, blank = True )
cr_date = models.DateTimeField(auto_now_add = True)
user = models.OneToOneField(to=User, on_delete=CASCADE, null=True, blank=True)
def __str__(self):
return "%s" % self.name
view.py
class HomeView(TemplateView):
template_name = "ahmed_drive/home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = self.request.user
home_folders = Folder.objects.filter(user=user).order_by('-cr_date')
home_files = Fileshare.objects.filter(uploaded_by=user).order_by('-id')
context['home_folders'] = home_folders
context['home_files'] = home_files
return context
#method_decorator(login_required, name="dispatch")
class FolderCreate(CreateView):
model = Folder
fields = ["name", "parent"]
def formvalid():
if form.is_valid():
form.save()
return redirect('home.html')
else :
return render(request,{'form': form})
home.html
{% extends 'base.html' %}
{% block content %}
{% for Folder in home_folders %}
<h1> {{Folder.name}} </h1>
{% endfor %}
{% endblock %}

when you create folder you don't connect user to it.
you need to do it before saving form
def form_valid(self, form):
folder = form.save(commit=False)
folder.user = request.user
folder.save()
return redirect('home.html')

Related

Dynamically render select choices Django

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

Django dropdown filter queryset with FilterView

I want to filter apartments by selecting subcity field in a dropdown in my django app. I'm using django-filters and django-bootstrap-form. But the dropdown does not populate with database querysets. How can I make the dropdown work?
models.py:
from django.contrib.sites.models import Site
from django.contrib.gis.db import models
from django.utils.crypto import get_random_string
from django.contrib.gis.geos import GEOSGeometry,Point
from django.contrib.auth.models import AbstractUser
from django.shortcuts import render
from django.urls import reverse
from django.forms import ModelForm
from django.template.defaultfilters import slugify
import datetime
from leaflet.forms.widgets import LeafletWidget
from django.contrib.gis.db import models as geo_models
# Create your models here.
class User(AbstractUser):
pass
geos_pnt=Point(4314498.56, 1003834.600,srid=3857)
#pnt=GEOSGeometry('POINT(4314498.56, 1003834.600)').wkt
class Apartment(models.Model):
ADKT='Addis Ketema'
AKLT='Akaki-Kality'
ARDA= 'Arada'
BOLE='Bole'
GLLE='Gulele'
KLFE='Kolfe-Keranio'
KIRK='Kirkos'
LDTA='Lideta'
YEKA='Yeka'
NFSL='Nefas Silk-Lafto'
SUBCITY_CHOICES = [
(ADKT, 'Addis Ketema'),
(AKLT, 'Akaki-Kality'),
(ARDA, 'Arada'),
(BOLE, 'Bole'),
(GLLE, 'Gulele'),
(KLFE, 'Kolfe-Keranio'),
(KIRK,'Kirkos'),
(LDTA, 'Lideta'),
(NFSL, 'Nefas Silk-Lafto'),
(YEKA, 'Yeka')]
apt_id = models.CharField(max_length=200, primary_key=True,editable=True)
geom = geo_models.PointField(null=True)
apt_area = models.IntegerField(default=0, null=True)
no_bedrooms = models.IntegerField(null=True)
apt_cost = models.IntegerField(default=0, null=True)
apt_subcity = models.CharField(default='KIRK',choices=SUBCITY_CHOICES,max_length=30,null=True)
register_date = models.DateTimeField(auto_now_add=True,null=True)
objects = models.Manager()
sites =models.ManyToManyField(Site)
#change points from apt_rent_db to kml
def pointkml(self):
points = Apartment.objects.kml()
return render("placemarks.kml", {'places': points})
def get_absolute_url(self):
return reverse('rent_app:apartment-listing', kwargs={'pk': self.pk})
def save(self, *args, **kwargs):
#self.Latitude = self..y
#self.Longitude = self.location.x
self.slug = slugify(self.apt_id)
super(Apartment, self).save(*args, **kwargs)
class Meta:
# order of drop-down list items
verbose_name = ("Apartment")
verbose_name_plural = ("Apartments")
ordering = ('apt_cost',)
app_label = 'rent_app'
def __unicode__(self):
return self.apt_id
#property
def picture_url(self):
return self.picture.url
class UserProfile(models.Model):
first_name = models.CharField(max_length=100, null=False)
last_name = models.CharField(max_length=100,null=False)
gender = models.CharField(max_length=100)
phone_no = models.CharField(max_length=12)
sites = models.ManyToManyField(Site)
views.py:
class ApartmentFilterView(FilterView):
model = Apartment
context_object_name = 'apartments'
filter_class = ApartmentFilter
filters.py:
import django_filters
from .models import Apartment,UserProfile
class ApartmentFilter(django_filters.FilterSet):
ADKT = 'Addis Ketema'
AKLT = 'Akaki-Kality'
ARDA = 'Arada'
BOLE = 'Bole'
GLLE = 'Gulele'
KLFE = 'Kolfe-Keranio'
KIRK = 'Kirkos'
LDTA = 'Lideta'
YEKA = 'Yeka'
NFSL = 'Nefas Silk-Lafto'
SUBCITY_CHOICES = [
(ADKT, 'Addis Ketema'),
(AKLT, 'Akaki-Kality'),
(ARDA, 'Arada'),
(BOLE, 'Bole'),
(GLLE, 'Gulele'),
(KLFE, 'Kolfe-Keranio'),
(KIRK, 'Kirkos'),
(LDTA, 'Lideta'),
(NFSL, 'Nefas Silk-Lafto'),
(YEKA, 'Yeka')]
ordering = django_filters.ChoiceFilter(label='Ordering',subcity_choices=SUBCITY_CHOICES, method='filter_by_ordering')
class Meta:
model = Apartment
fields = {
'apt_cost': ['lte'],
#'apt_dist': ['lt'],
'apt_subcity': ['icontains'],
}
template:
{% extends 'base.html' %}
{% load bootstrap %}
{% block title %} የተገኙ ቤቶች | Apartment List {% endblock title %}
{% block content %}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit">
</form>
{% for obj in filter.qs %}
{{obj.apt_id}} - Birr {{obj.apt_cost}}
{% endfor %}
{% endblock %}
Your model should be listed in the Meta class.
class yourfilter(django_filters.FilterSet):
class Meta:
model = your_model

Django if statement in DetailView returns False

The main problem for me was: If a user is the owner of the prime then it should return True. But it always returns False.
My models.py:
from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
class Prime(models.Model):
prime_owner = models.ForeignKey(User, null=True)
prime_name = models.CharField(max_length=100)
prime_address = models.CharField(max_length=250)
My views.py:
class PrimeDetails(generic.DetailView):
template_name ='prime/primedetails.html'
model = Prime
def get_context_data(self, **kwargs):
context = super(PrimeDetails, self).get_context_data(**kwargs)
user = self.request.user
prime_owner = Prime.prime_owner
if user == prime_owner:
owner = True
else:
owner = False
context['owner'] = owner
return context
primedetails.html
{% extends 'prime/base.html' %}
{% block content %}
<div class="container">
<h1>{{ owner }}</h1>
<h1>{{object.prime_name }}</h1>
<h3>{{object.prime_address}}</h3>
</div>
{% endblock %}
Prime is a model, not the object.
Try change the Prime to self.get_object(), like this:
def get_context_data(self, **kwargs):
context = super(PrimeDetails, self).get_context_data(**kwargs)
user = self.request.user
prime_owner = self.get_object().prime_owner
if user == prime_owner:
owner = True
else:
owner = False
context['owner'] = owner
return context

Why is this Django class-based year archive view not working?

I'm trying to subclass the YearArchiveView class-based view to show a list of articles published in a year, but the filtering doesn't work and example.com/2012 shows articles from all years.
Note that I do not want the view code in urls.py. Rather, I want the LogbookYearArchive wrapper to continue living in views.py.
models.py:
class Entry(models.Model):
KIND = (
('L', 'Link'),
('A', 'Article'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(unique_for_date='pub_date')
kind = models.CharField(max_length=1, choices=KIND, default=1,
help_text="Is this a link to other content or an original article?")
url = models.URLField(blank=True, help_text="The link URL")
body = models.TextField(blank=True)
body_html = models.TextField()
content_format = models.CharField(choices=CONTENT_FORMAT_CHOICES,
max_length=50, default=1)
is_active = models.BooleanField(help_text=_("Tick to make this entry\
live (see also the publication date). Note that administrators\
(like yourself) are allowed to preview inactive entries whereas\
the general public aren't."), default=True)
pub_date = models.DateTimeField(verbose_name=_("Publication date"),
help_text=_("For an entry to be published, it must be active and its\
publication date must be in the past."))
mod_date = models.DateTimeField(auto_now_add=True, editable=False)
class Meta:
db_table = 'blog_entries'
verbose_name_plural = 'entries'
ordering = ('-mod_date',)
get_latest_by = 'pub_date'
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
"""Construct the absolute URL for an Entry of kind == Article."""
return ('logbook-entry-detail', (), {
'year': self.pub_date.strftime("%Y"),
'month': self.pub_date.strftime("%m"),
'slug': self.slug})
urls.py:
from __future__ import absolute_import
from django.conf.urls import patterns, include, url
from .models import Entry
from .views import LogbookYearArchive
urlpatterns = patterns('',
url(r'^(?P<year>\d+)/$',
view=LogbookYearArchive.as_view(),
name='archive-year'),
)
views.py:
from django.views.generic.list import MultipleObjectMixin
from django.views.generic import ArchiveIndexView, MonthArchiveView, YearArchiveView, DetailView
from django.core.urlresolvers import reverse
from .models import Entry
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
def get_context_data(self, **kwargs):
context = super(LogbookYearArchive, self).get_context_data(**kwargs)
# =todo: fix filtering by date which is not working
context['object_list'] = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')[:9999]
return context
archive_year.html:
{% block content %}
<h1 style="margin-bottom:1em;">Articles Published in {{ year|date:"Y" }}</h1>
{% for object in object_list %}
{% ifchanged %}
<h2 class="dateline datelinearchive">{{ object.pub_date|date:"F Y" }}</h2>
{% endifchanged %}
<p>
{{ object.title }}
</p>
{% endfor %}
{% endblock %}
Can you try this:
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
queryset = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')
I added a queryset attribute and removed get_context_data()
I had the same problem. All ArchiveViews were working except YearArchiveView. Solution was found in make_object_list property. It should be True
That's a cut from django code
if not self.get_make_object_list():
# We need this to be a queryset since parent classes introspect it
# to find information about the model.
qs = qs.none()

Django 'PictureForm' object has no attribute 'save'

I'm trying to add a new feature to my existing app that let users create a profile and upload a pictures of their pets.
When a user login , he gets redirected into the profile which display his name and also he can add a picture of himself into the model which will get displayed on the profile page.
At the moment , I can retrieve the name into the template but I can't seem to display the user's name and upload picture at the same time.
Whenever I click Add picture , It doesn't let the user upload a picture instead I get this error
'PictureForm' object has no attribute 'save'
pet = form.save(commit =False) ...
I could design the page to let the user upload a picture but not display the name at the same time.
I think the problem lays in my profile.html and Profile function at views.py
Parts of my views.py
#login_required
def Profile(request):
Person = request.user.get_profile()
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
if request.method == "POST":
form = PictureForm(request.POST ,request.FILE or None)
if form.is_valid():
pet = form.save(commit =False)
pet.save()
context = (
{'Person': Person} ,
{'form':PictureForm()}
)
return render_to_response('profile.html', context, context_instance=RequestContext(request))
Parts of my forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
from pet.models import *
class PictureForm(forms.Form):
class Meta:
model = Person
fields = ('image')
My profile.html
{% if Person %}
<ul>
<li>Name : {{Person.name}} </li>
</ul>
{% endif %}
<form method="POST" enctype="multipart/form-data" "action" >
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type = "submit" value= "Add Picture" />
</form>
My models.py
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User
class Person(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
def __unicode__(self):
return self.name
class Pet(models.Model):
Person = models.ForeignKey(Person)
description = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
def __unicode__(self):
return self.description
PictureForm needs to inherit from forms.ModelForm, not forms.Form.
Erase your form.save(commit=False). You will only do that if you override your save method
#login_required
def Profile(request):
Person = request.user.get_profile()
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
if request.method == "POST":
form = PictureForm(request.POST ,request.FILES)
if form.is_valid():
form.save()
context = (
{'Person': Person} ,
{'form':PictureForm()}
)
return render_to_response('profile.html', context, context_instance=RequestContext(request))
UPDATE:
[.....]
board = Board.objects.get(board=picture.board)//remove this
the_id = board.id //remove this
return HttpResponseRedirect(reverse('world:Boat', kwargs={'animal_id': picture.board.id })) // change the_id into picture.board.id
You have a typo. It should be request.FILES.
no buddy. your problem is in your model.py:
just add this function to your model
def save(self,*args, **kw):
super(PictureForm,self).save(*args, **kw)