foreignkey backwards manager not working django - django

This seems simple.. I have a Restaurant model and Recipe model, all I want is to be able to look up all the Recipes by a certain Restaurant. I am using the backwards manager FOO_set and cant seem to make it work:
models.py
class Restaurant(models.Model):
restaurant_user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='restaurant')
class Recipe(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, related_name='recipe')
views.py
def dashboard(request):
user = request.user
try:
user.restaurant
recipe_list = user.restaurant.recipe_set
return render(request, 'usermanage/dashboard_restaurant.html',{'recipe_list':recipe_list})
When i run this i get an exception in the dashboard view. Looking at my database the user.restaurant object has recipes associated with it. If i just do recipe_list = user.restaurant it returns the restaurant object. Just when I add recipe_set it fails. Also tried recipe_set.all and all(). I have migrated everything. Django 1.11

you set related_name so you need to use it:
replace:
recipe_list = user.restaurant.recipe_set
# ^^^^^
to
recipe_list = user.restaurant.recipe.all()
# ^^^^^^

Related

Django) How to connect urls-views-models in ManyToMany, OneToMany relationship

I made some models which have ManyToMany, OneToMany relationships, and then I tried to make appropriate class in views.py, so that one can see sub models related to the chosen model.
But in terms of connecting models-serializers-views-urls, I just couldn't figure out how to make it work...
So, what I want to do is : (simplified)
There are 3 models.
Party
People
Food
So Party has ManyToMany relationship with People, and OneToMany relationship with Food. When I reached url like /party_id/people_id, then I want to get specific person's information from given party id.
Here goes my code.
models.py
class Party(models.Model):
par_id = models.TextField()
par_people = models.ManyToManyField(People)
class People(models.Model):
peo_id = models.TextField()
peo_name = models.TextField()
peo_type = models.TextField()
class Food(models.Model):
foo_id = models.TextField()
foo_party = models.ForeignKey(Party, on_delete=models.CASCADE)
serializers.py
class PartySerializer(serializers.ModelSerializer):
class Meta:
model = Party
fields = ('par_id', 'par_people')
# People, Food has same structure...
views.py
class PartyList(generics.ListAPIView):
queryset = Party.objects.all()
serializer_class = PartySerializer
# People, Food has same structure...
urls.py
Here's the part where I got lost
#redundancy reduced...(e.g. import)
urlpatterns = [
path('party/<int:par_id>/<int:peo_id>', views.PartyList.as_view()),
path('party/<int:par_id>/<int:foo_id>', views.PartyList.as_view()),
]
So If I reach website/party/1/3, I want to see person's information(whose peo_id is 3) of party(whose par_id is 1). For food, It goes the same.
Should I make new class in views.py to make it work? But how can url check par_id and foo_id at the same time if I use PartyList view class..? Any help would be much appreciated.
I think something like this should work. The basic principle if work out if using peo_id or foo_id and then filter the queryset on that basis.
def get (self, *args, **kwargs):
id = kwargs.get(peo_id, None)
if id:
self.queryset.filter(par_people__peo_id=id)
else:
id = kwargs.get(foo_id, None)
self.queryset.filter(foo_party=id)

How do I link these two models such that one will update that same instance?

I really want to build this app with Django that lets people register and create User instances that can be edited. Each User instance is already linked to a UserProfile with OneToOne because I didn't want to mess with the original User model. The UserProfile will have a field where he/she can register a game if that person is logged in.
ie. Billy wants to register for Monday Smash Melee. He logs in, clicks an option on a form, the UserProfile linked to User, Billy, will update the registered game choice and user tag to the user profile.
The part with the user profile linking to the user works fine, but I don't know how to update the UserProfile with the new tournament registration form so that it can change the UserProfile fields that's linked to the user that is logged in.
Django Models:
class UserProfile(models.Model):
#User profile for registered users. SEPARATE USERBASE TO PLAYER_RANKING
#To Do: add more customizeability and more access for registered.
#weekly e-mails, ability to register for weeklies...
user = models.OneToOneField(User)
picture = models.ImageField(upload_to='profile_images', blank=True)
MON = 'ME'
TUE = 'S4'
THR = 'PM'
reg_game_choices = (
(MON, "Melee"),
(TUE, "Smash 4"),
(THR, "PM"),
)
reg_game_choice = models.CharField(max_length=2,
choices=reg_game_choices,
default="")
user_tag = models.CharField(max_length=60, default = "")
def __str__(self):
return self.user.username
Forms:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('picture',)
class TournyRegForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('reg_game_choice', 'user_tag',)
View:
#login_required
def tourny_reg(request):
#Registering for tournaments
context_dict = {}
weekday = datetime.datetime.today().weekday()
day_names = ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']
game_days = ['SMASH MELEE', 'SMASH 4', 'CLOSED', 'PROJECT M & FIGHTING GAMES',
'FRIENDLIES', 'CLOSED', 'CLOSED']
day_title = day_names[weekday]
game_day = game_days[weekday]
context_dict['day'] = day_title
context_dict['game_of_the_day'] = game_day
if request.method == 'POST':
tourny_form = TournyRegForm(data=request.POST)
if tourny_form.is_valid():
tourny_form.save()
else:
print (tourny_form.errors)
else:
tourny_form = TournyRegForm()
context_dict['tourny_form'] = tourny_form
return render(request, 'Kappa/tourny_reg.html', context_dict)
It shows up perfectly fine in html and on the local server, but when I try, it gives me an integrity error.
IntegrityError at /Kappa/tourny_reg/
NOT NULL constraint failed: Kappa_userprofile.user_id
Exception Value:
NOT NULL constraint failed: Kappa_userprofile.user_id
▶ Local vars
C:\Users\Kyle\Documents\GitHub\Kappa_Ranks\Kappa\views.py in tourny_reg
So basically, you want to know how to save an instance of something which is related to the logged-in user. That's easy.
To explain why you are getting a NOT NULL error: Your TournyRegForm class has not been told to display an input field for 'user', so it isn't. So when you go to save the form, None is being filled in for the user field. The database is complaining because a 'NOT NULL' field has a NULL value, which is a problem.. so this error is legitimate.
But it's ok that this field is not on the form.. because you don't want the user telling us who they are via the form, you want to get the information about who they are by the fact that they are logged in. The Django auth module puts this information in the Request object where you can easily get at it. All you need to do is to fill in the correct user before the model is saved, like this:
if tourny_form.is_valid():
# commit= False tells the modelform to just create the model instance
# but don't save it yet.
user_profile = tourny_form.save(commit=False)
# associate this user_profile with the logged in user.. it is always
# present in the request object if you are using django's auth module.
user_profile.user = request.user
# now save it
user_profile.save()
So that takes care of saving a model that is related to the currently logged in user. But you have other problems. For example, do you want to save a new UserProfile each time? I don't think you do.. So on your GET you need to do something like this:
user_profile = UserProfile.objects.filter(user=request.user).first()
tourny_form = TournyRegForm(instance=user_profile)
This will fetch the UserProfile of the currently logged=in user from the database, then initialize the form with that instance, so when the user comes back they will be able to edit their profile.
Now, if you actually want the user to be able to register for multiple games.. you will need a Game model for storing the game information, with one-to-many relationship with your UserProfile. This works by having a ForeignKey field in the Game model which relates it to UserProfile.. so each user will have only one UserProfile but could have multiple Games.

ForeignKey field will not appear in Django admin site

A foreign key on a model is not appearing in the Django admin site. This is irrespective of whether the field is explicitly specified in a ModelAdmin instance (fields = ('title', 'field-that-does-not-show-up')) or not.
I realize there are many variables that could be causing this behavior.
class AdvertiserAdmin(admin.ModelAdmin):
search_fields = ['company_name', 'website']
list_display = ['company_name', 'website', 'user']
class AdBaseAdmin(admin.ModelAdmin):
list_display = ['title', 'url', 'advertiser', 'since', 'updated', 'enabled']
list_filter = ['updated', 'enabled', 'since', 'updated', 'zone']
search_fields = ['title', 'url']
The problem is the advertiser foreign key is not showing up in the admin for AdBase
class Advertiser(models.Model):
""" A Model for our Advertiser
"""
company_name = models.CharField(max_length=255)
website = models.URLField(verify_exists=True)
user = models.ForeignKey(User)
def __unicode__(self):
return "%s" % self.company_name
def get_website_url(self):
return "%s" % self.website
class AdBase(models.Model):
"""
This is our base model, from which all ads will inherit.
The manager methods for this model will determine which ads to
display return etc.
"""
title = models.CharField(max_length=255)
url = models.URLField(verify_exists=True)
enabled = models.BooleanField(default=False)
since = models.DateTimeField(default=datetime.now)
expires_on=models.DateTimeField(_('Expires on'), blank=True, null=True)
updated = models.DateTimeField(editable=False)
# Relations
advertiser = models.ForeignKey(Advertiser)
category = models.ForeignKey(AdCategory)
zone = models.ForeignKey(AdZone)
# Our Custom Manager
objects = AdManager()
def __unicode__(self):
return "%s" % self.title
#models.permalink
def get_absolute_url(self):
return ('adzone_ad_view', [self.id])
def save(self, *args, **kwargs):
self.updated = datetime.now()
super(AdBase, self).save(*args, **kwargs)
def impressions(self, start=None, end=None):
if start is not None:
start_q=models.Q(impression_date__gte=start)
else:
start_q=models.Q()
if end is not None:
end_q=models.Q(impression_date__lte=end)
else:
end_q=models.Q()
return self.adimpression_set.filter(start_q & end_q).count()
def clicks(self, start=None, end=None):
if start is not None:
start_q=models.Q(click_date__gte=start)
else:
start_q=models.Q()
if end is not None:
end_q=models.Q(click_date__lte=end)
else:
end_q=models.Q()
return self.adclick_set.filter(start_q & end_q).count()
class BannerAd(AdBase):
""" A standard banner Ad """
content = models.ImageField(upload_to="adzone/bannerads/")
The mystery deepens. I just tried to create a ModelForm object for both AdBase and BannerAd, and both generated fields for the advertiser. Some crazy admin things going on here...
I believe I've just run into exactly the same problem, but was able to debug it thanks to the help of persistent co-workers. :)
In short, if you look in the raw HTML source you'll find the field was always there - it's just that:
Django tries to be clever and put the form field inside a div with CSS class="form-row $FIELD_NAME",
The field's name was "advertiser", so the CSS class was "form-row advertiser",
...Adblock Plus.
Adblock Plus will hide anything with the CSS class "advertiser", along with a hell of a lot of other CSS classes.
I consider this a bug in Django.
maybe it is an encode error. I had the same problem, but when i added # -- coding: UTF-8 -- in the models.py, all fine.
Another very dumb cause of the same problem:
If there is only one instance of the related model, then the filter simply won't show. There is a has_output() method in RelatedFieldListFilter class that returns False in this case.
It's a strange problem for sure. On the AdBase model if you change
advertiser = models.ForeignKey(Advertiser)
to
adver = models.ForeignKey(Advertiser)
then I believe it'll show up.
Powellc, do you have the models registered with their respective ModelAdmin class?
admin.site.register(Advertiser, AdvertiserAdmin) after the ModelAdmin definitions.
You are talking about the list_display option, right?
Is the unicode-method for your related model set?
If the field is a ForeignKey, Django
will display the unicode() of the
related object
Also check this thread for some hints: Can "list_display" in a Django ModelAdmin display attributes of ForeignKey fields?
Try disabling your ad blocker. No, this is not a joke. I just ran into this exact problem.
We just ran into this problem.
It seems that if you call you field advertiser the in the admin the gets given an 'advertiser' class.
Then is then hidden by standard ad blocking plugins. If you view source your field will be there.

Django retrieve all comments for a user

I'm using django-profiles and django.contrib.comments and I am trying to display all comments for a particular user in their profile.
This is using the default profile_detail view from django-profiles.
I've tried these two approaches and neither is returning any objects (although objects matching this query do exist):
{% for comment in profile.user.comment_set.all %}
and
{% for comment in profile.user.user_comments.all %}
In the source code for django.contrib.comments, the foreign key to user in the Comment model has the following related name:
user = models.ForeignKey(User, verbose_name=_('user'),
blank=True, null=True, related_name="%(class)s_comments")
Comments also has a custom manager:
# Manager
objects = CommentManager()
Which is defined as:
class CommentManager(models.Manager):
def in_moderation(self):
"""
QuerySet for all comments currently in the moderation queue.
"""
return self.get_query_set().filter(is_public=False, is_removed=False)
def for_model(self, model):
"""
QuerySet for all comments for a particular model (either an instance or
a class).
"""
ct = ContentType.objects.get_for_model(model)
qs = self.get_query_set().filter(content_type=ct)
if isinstance(model, models.Model):
qs = qs.filter(object_pk=force_unicode(model._get_pk_val()))
return qs
Is the custom manager causing the .all query not to return anything? Am I accessing the reverse relation correctly? Any help would be appreciated.
The related name is defined so the default name_set will not work. The purpose of related_name is to override that default reverse manager name.
user = models.ForeignKey(User, verbose_name=_('user'),
blank=True, null=True, related_name="%(class)s_comments")
So use this:
user.comment_comments.all()

Filter products by attribute

I'm working on an eshop with Satchmo framework.
Does anyone know what steps should i follow in order to filter products according to a custom attribute(type of material) in order to present the products that have the same kind of material in a page(material.html)?
Should i make a material_view function
Should i override get_absolute_url function?
If you want to do this without touching the core code, I would make a local app localsite/product and in models.py:
class Material(models.Model):
product = models.ManyToManyField(Product, blank=True, null=True)
name = models.CharField(_("Name"), max_length=30)
slug = models.SlugField(_("Slug"), help_text=_("Used for URLs, auto-generated from name if blank"), blank=True, unique=True)
description = models.TextField(_("Description"), blank=True, help_text="Optional")
Add this new app to your admin, and to additionally make them available from the product page, add them as inline:
# if you have lots of products, use the nice horizontal filter from django's admin
class MaterialAdmin(admin.ModelAdmin):
filter_horizontal = ('product',)
class Material_Inline(admin.TabularInline):
model = Material.product.through
extra = 1
admin.site.register(Material, MaterialAdmin)
# Add material to the inlines (needs: from product.admin import Product, ProductOptions)
ProductOptions.inlines.append(Material_Inline)
admin.site.unregister(Product)
admin.site.register(Product, ProductOptions)
Then you can adapt your views/urls:
# urls.py
url(r'^material-list/([\w-]+)/$', material_list, {}, name="material_list"),
# view.py
def material_list(request, slug):
products = Product.objects.filter(material__slug='slug')
return render_to_response('localsite/material/list.html', {'products':products}, context_instance=RequestContext(request))
When you say "custom attribute" do you mean that you have modified the product.models.Product code to add another field?
If that is the case you'll probably want to create a custom view.
If your Product code is something like...
class Product(models.Model):
...
matieral_type = models.CharField(max_length=128)
...
...then you can build a view like this...
def material(request,material_type):
prods = Product.objects.filter(material_type=material_type)
return render_to_response('material.html',{'products',prods},RequestContext(request))