I am trying to create a function that allows individuals to post something on an associated userpage. I have created both the model ‘newpost’ and ‘newpostform’ (below). I am having trouble writing the view function to look at the current URL of the page and then take that parameter and attach it to the newpost model’s ForeignKey field automatically. For example, if I am at the URL myapp.com/userpage1 and I click on the “post” button on that page, I want to create a newpost object which automatically has the ForeignKey field filled in as ‘userpage1’. Basically, I am trying to create an app where people can easily navigate userpages by entering the userpage parameter into the URL and easily make posts on those pages quickly and concisely - kind of like how reddit's subreddit system works by entering the name of the subreddit into the URL bar. Thanks for any help and hints.
model:
class newpost(models.Model):
newlinktag = models.ForeignKey(‘userpage’) #tags link to which userpage the post belongs to
postcontent = models.CharField(max_length=1024)
postdate = models.DateTimeField(auto_now_add=True) #submission timestamp.
postlikes = models.IntegerField(null=False, default=0)
def __unicode__(self):
return self.postcontent
form:
class newpostform(forms.ModelForm):
postcontentform = models.CharField(max_length=1024)
class Meta:
model = newpost
urls.py:
url(r'^(?P<url_user_id>[\w\-]+)/$', your_view)
views.py
def your_view(request, url_user_id)
# you have the foreign key in the url_user_id field.
...
if request.POST:
new_post_with_foreign_key = newpost(newlinktag=url_user_id, ...)
...
new_post_with_foreign_key.save()
Don't do this in the form. Exclude the FK field from the modelform altogether, and set it in the view on save.
if form.is_valid():
post = form.save(commit=False)
post.newlinktag = page
post.save()
(You might like to consider following PEP8 and using some CapitalLetters in your class names, and underscore_names in your field names. It'll make your code much easier to read.)
Related
we can submit foriegnkey data to models
through ModelForm
class BooksForm(forms.ModelForm):
class Meta:
model = Books
fields = "__all__"
where in templates we can add
{{form.author}} (author is foriegnkey field in books model)
Im aware that we can submit foriegnkey data using forms like this
but my question is.is there any way where we can submit a foriegnkey object which we have fetched using some other method (with or without form )
to a model(in my case its book)
Let me explain it in detail
lets say for instance there is a Search bar
when users search for author,
then the function fetches list of authors (choice field) to the user
where user can select and submit
which should get populated in the books model
there isnt any proper info related to this on web
all i could see is information on how to save data with Foriegnnkey using model form
any kind of insights is appreciated
I'm not 100% sure what your desired outcome is - this is how I understand your issue:
If you want to create a Book entry while passing an Author instance along you could set it as follows:
# models.py
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
author = models.ForeignKey('Author', on_delete=models.CASCADE)
title = models.CharField(max_length=50)
# views.py
def example_view(request):
selected_author_instance = Author.objects.get(pk=1) # example query, adjust to your needs
# Create Book instance and pass author instance along
book_instance = Book.objects.create(
author=selected_author_instance,
title='example'
)
book_instance.save()
return render(...)
I have created a posts list where users can simply create a post, upload a photo and similar to StackOverflow, they can assign "Tags" to their post to categorise their post (I am using Tagulous library to power the tags feature of my application)
At the moment users can assign tags to their Post. However, what I am wanting to achieve is the following:
When a user creates a Post in a specific tag, I want to filter the overall Posts view, based on the past tags they have assigned to their previous posts. E.g. If User A assigns a tag called "Winter" to their Post, after submitting their post, they will see any other Posts on their Post Feed which are relevant to the "Winter" tag.
If in the future, they decide to assign one or more other tags to any future posts they create, those posts sharing the same tag name will also appear on their Post Feed.
In a nutshell, for every one tag which the user self assigns to any future post, they will begin to see Posts of other users who are using the same tag within their posts.
Where I am at, at the moment is:
I have created a public Post View (A feed of where all my posts are displayed arranged by date order)
I have created a view for where posts can be created and I have integrated Tagulous in to my Post Creation view.
Now, I am just trying to figure how to filter my posts based on which Tagulous tags the user has self assigned to their previous posts on my application.
Here is my code so far:
Models.py
class Post(models.Model):
content = models.TextField(max_length=1000)
date_posted = models.DateTimeField(default=timezone.now)
image = models.ImageField(default='default.png', upload_to='media')
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes= models.IntegerField(default=0)
dislikes= models.IntegerField(default=0)
title = tagulous.models.SingleTagField(initial="test1, test2, test3")
season = tagulous.models.TagField(
autocomplete_view='tags_season_autocomplete'
)
Views.py
class PostListView(LoginRequiredMixin, ListView):
model = Post
template_name = 'core/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = PAGINATION_COUNT
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
all_users = []
data_counter = Post.objects.values('author')\
.annotate(author_count=Count('author'))\
.order_by('-author_count')[:6]
for aux in data_counter:
all_users.append(User.objects.filter(pk=aux['author']).first())
data['preference'] = Preference.objects.all()
# print(Preference.objects.get(user= self.request.user))
data['all_users'] = all_users
print(all_users, file=sys.stderr)
return data
def get_queryset(self):
user = self.request.user
qs = Follow.objects.filter(user=user)
follows = [user]
for obj in qs:
follows.append(obj.follow_user)
return Post.objects.filter(author__in=follows).filter(season__name__in=['Winter']).order_by('-date_posted')
At the moment as seen in the last line of my Views.py file, I have managed to filter my Post Feed view based on manually defining the tag name (Although my goal here is to "get" all the tags from the "Posts" in which the user has created in the past and in return, filter the user's post feed based on the tags he has previously assigned to his or her previous posts on the application.
Any suggestions or pointers would be most appreciated!
(I have been referencing this source for ideas with forming a solution to my challenge - https://radiac.net/projects/django-tagulous/documentation/models/tagged_models/)
Thank you :-)
UPDATE:
So after a little more digging in to Tagulous, I have managed to change the last line of my views.py file to this:
return Post.objects.filter(author__in=follows).filter(season__author=self.request.user).order_by('-date_posted')
It's still not quite right as I am now receiving an error which says, "Cannot query must be an instance of Tagulous_Post_season"`
Could anyone suggest a method of what would be the most suitable way to create the instance?
Thanks!
I followed this: https://www.yergler.net/2009/09/27/nested-formsets-with-django/ and this: django inline formsets with a complex model for the nested form and overall my code works great.
class Account(models.Model):
user_username = models.ForeignKey(User, on_delete=models.CASCADE)
account_name = models.CharField(max_length=30)
class Classification(models.Model):
user_username=models.ForeignKey(User, on_delete=models.CASCADE)
data_id=models.ForeignKey(ImportData, on_delete=models.CASCADE)
class ImportData(models.Model):
user_username = models.ForeignKey(User, on_delete=models.CASCADE)
data_id = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False)
ClassificationFormset = inlineformset_factory(ImportData, Classification, exclude=('user_username',), extra=1)
# below is just what came from the nested formset links above: pasted here for easy reference.
class BaseNestedTransactionFormset(BaseInlineFormSet):
def add_fields(self, form, index):
# allow the super class to create the fields as usual
super(BaseNestedTransactionFormset, self).add_fields(form, index)
try:
instance = self.get_queryset()[index]
pk_value = instance.pk
except IndexError:
instance=None
pk_value = hash(form.prefix)
transaction_data = None
if (self.data):
transaction_data = self.data;
# store the formset in the .nested property
form.nested = [
CategoryFormset(data=transaction_data,
instance = instance,
prefix = 'CAT_%s' % pk_value)]
def is_valid(self):
result = super(BaseNestedTransactionFormset, self).is_valid()
for form in self.forms:
if hasattr(form, 'nested'):
for n in form.nested:
# make sure each nested formset is valid as well
result = result and n.is_valid()
return result
def save_new(self, form, commit=True):
"""Saves and returns a new model instance for the given form."""
instance = super(BaseNestedTransactionFormset, self).save_new(form, commit=commit)
# update the form’s instance reference
form.instance = instance
# update the instance reference on nested forms
for nested in form.nested:
nested.instance = instance
# iterate over the cleaned_data of the nested formset and update the foreignkey reference
for cd in nested.cleaned_data:
cd[nested.fk.name] = instance
return instance
def save_all(self, commit=True):
"""Save all formsets and along with their nested formsets."""
# Save without committing (so self.saved_forms is populated)
# — We need self.saved_forms so we can go back and access
# the nested formsets
objects = self.save(commit=False)
# Save each instance if commit=True
if commit:
for o in objects:
o.save()
# save many to many fields if needed
if not commit:
self.save_m2m()
# save the nested formsets
for form in set(self.initial_forms + self.saved_forms):
# if self.should_delete(form): continue
for nested in form.nested:
nested.save(commit=commit)
ImportTransactionFormset = inlineformset_factory(Account, ImportData, exclude=('user_username',), formset=BaseNestedTransactionFormset, extra=0)
My template has a table that displays the import data formset... user selects the account and the table shows all the imported data from that account. For each of these row forms, there is a hidden row underneath... user clicks a button to show that hidden row. The hidden row displays the nested classification formset.
If include the user_username field in the template and allow for it to be part of the nested formset in the template, i can set is accordingly in the html form and the formsets save no problem.
However: I want to be able to exclude the user_username field from the template and have my view or some other method under the BaseNestedTransactionFormset class set the value of the user_username field to request.user value for whoever is logged in at that time.
I tried to override the clean method, but cleaned_data kicks back an error because the form doesnt validate; the field is required. I can't seem to figure out a good way to do this.
If this was a normal formset, not too hard to do. I would just set the field by modifying what comes back from POST. I have never worked with nested inline formsets, and the prefixes and indeces in the field names have got me. I've been at this for a couple of days and can't seem to be getting anywhere.
I am also contemplating just getting rid of that field from the classification model, since it is already tied to the ImportData model which is linked to the logged in user regardless. I'm just thinking i may run into this at some point again, so maybe good to solve.
Thanks in advance.
I am new at Django and I have tried my best to understand it but I still have a long way to go.
I am working on a project in which I have to make a webpage where I have to display data from these classes :
class team(models.Model):
team_name = models.CharField(max_length = 40)
def __unicode__(self):
return self.team_name
class metric(models.Model):
team = models.ForeignKey(team)
metric_name = models.CharField(max_length = 40)
def __unicode__(self):
return self.metric_name
class members(models.Model):
metric = models.ForeignKey(metric)
member_ID = models.CharField(max_length = 40)
member_name = models.CharField(max_length = 40, null=True, blank=True)
def __unicode__(self):
return self.member_ID
Furthermore I want this data to be editable as well. Meaning there should be an Edit button which once pressed would enable the user to edit these fields and once he saves it the database get's updated automatically.
Now as far as I have understood. I would need to display this data using tables of some sort and then once the user clicks on the Edit button I would have to change the Tables into form so he can edit the data ? and then update the database once he clicks on save.
I am not sure how to do all this in Django.
If anyone could please refer to me step by step on how to proceed and maybe refer to some References It would help me a lot
Thanks :)
UPDATE: I forgot to mention it before. I have already created a page where user selects team_name.. Then he is redirected to another page where I want to show the table for that specific team. And I also want that page to be editable. If I use modelforms then I won't be able to access single object of my team model.
UPDATE2: I am still stuck at this. I can't understand on how to display just few elements and variables of a model class rather then all of it. Apart from that I can't understand how to create a Form that can take input from the user on which object of the database to edit and then display that certain objects to be editable.
Related to the questioneers-comments here and here.
First of all, you should write your class-names capitalized. Please check the documentation.
You create Forms for a queryset like this.
forms.py
from django.forms import ModelForm
class MembersForm(ModelForm):
class Meta:
model = Members
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('yourapp.views',
url(r'^$',
# /
view = 'index',
name = 'team-index',
),
url(r'^(?P<lookup_team>[-\w]+)/$',
# .../team-extreme/
view = 'update',
name = 'update-members',
),
)
views.py (of your application)
from django.http import HttpResponse
from django.template.context import RequestContext
from django.shortcuts import render_to_response, reverse, redirect
from yourapp.models import Members
from yourapp.forms import MembersForm
def index(request):
queryset = Members.objects.all()
template = 'yourapp/index.html'
kwvars = {
'data': queryset,
}
return render_to_response(template, kwvars, RequestContext(request))
def update(request, lookup_team):
"""change members being in a special team"""
queryset = Members.objects.filter(metric__team__team_name=lookup_team)
if request.POST:
form = MemberForm(request.POST, instance=queryset)
if form.is_valid():
form.save()
return redirect(reverse('team-index'))
else:
form = MemberForm(instance=queryset)
template = 'yourapp/update.html'
kwvars = {
'form': form,
}
return render_to_response(template, kwvars, RequestContext(request))
Hope this helps. If you got any questions hit me a comment.
If you want to implement it as dynamically as you describe, then this is impossible by Django alone; Django can serve you the table and the forms, but a dynamic change without reloading the page (which I'm guessing is what you really want) needs some client side code, JavaScript.
But about showing the data and the forms: use Django's class based generic views.
The ListView and DetailsView should get you started with showing the data from the models.
The ModelForm in combination with the appropriate generic editing views should get you going with editing the data.
These views will, per default, return the data in some - generally useful - format and can be customized by using your own template. I suggest you read up on the links I provided you and work from there. That should get you going.
I'm struggling to get my head round django forms.. I've been reading various documentation but just can't quite grasp the concepts. I have got to grips with models, views and templates. What I am trying to do is to create a form with various fields composing of dropdown lists and checkboxes which are populated by values in a database.
I have a working app called vms. Using the models.py I have a built a simple schema that holds size and type. Size consists of 'small', 'medium' & 'large'. Type is 'windows' & 'linux'. Using the admin site, I can add an extra size, for example 'Extra Large'.
What I would like to do is create a form that has a drop down list of the vm sizes. If an extra size gets added via the admin site, I would like that size to appear in the drop down list.
I would submit my attempts at the code, but actually am struggling with the concepts. Can anyone help guide me in how to accomplish the above?
Thanks
Oli
Forms are just a tool to simplify and speed-up (the development of) the process of fetching POST data from the request. A manual way would be to do request.POST.get('somefield') for all the fields there are in some HTML form. But Django can do better than that...
In its essence, a Form class holds a number of Fields and performs these tasks:
display HTML inputs,
collect and validate data when user submits it,
if fields don't validate, return the values along with error messages to HTML,
if all fields validate, provide form.cleaned_data dictionary as a convenient way to access these values in view.
With these values, I could then manually create a new instance of a MyModel and save it. Of course, I would have to define a Field in the Form for every Field in MyModel model.
This means that, basically, I could do something like this:
(forgive me for not testing this code, so I can't vouch that it's 100% correct)
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class FormForMyModel(forms.Form):
form_field1 = forms.CharField(max_length=40, required=True)
form_field2 = forms.CharField(max_length=60, required=False)
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = FormForMyModel(request.POST)
if form.is_valid():
my_model = MyModel()
my_model.field1 = form.cleaned_data.get('form_field1', 'default1')
my_model.field2 = form.cleaned_data.get('form_field2', 'default2')
my_model.save()
else:
form = FormForMyModel()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
(this could be written with a few lines of code less, but it's meant to be as clear as possible)
Notice there are no relation between model Fields and form Fields! We have to manually assign values to MyModel instance when creating it.
The above example outlines generic form workflow. It is often needed in complex situations, but not in such a simple one as is this example.
For this example (and a LOT of real-world examples), Django can do better than that...
You can notice two annoying issues in the above example:
I have to define Fields on MyModel and Fields on FormForMyModel separately. However, there is a lot of similarity between those two groups (types) of Fields, so that's kind of duplicate work. The similarity grows when adding labels, validators, etc.
creating of MyModel instance is a bit silly, having to assign all those values manually.
This is where a ModelForm comes in.
These act basically just like a regular form (actually, they are extended from regular forms), but they can save me some of the work (the two issues I just outlined, of course :) ).
So back to the two issues:
Instead of defining a form Field for each model Field, I simply define model = MyModel in the the Meta class. This instructs the Form to automatically generate form Fields from model Fields.
Model forms have save method available. This can be used to create instance of model in one line in the view, instead of manually assigning field-by-field.
So, lets make the example above with a ModelForm:
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class MyModelForm(forms.ModelForm): # extending ModelForm, not Form as before
class Meta:
model = MyModel
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
# save the model to database, directly from the form:
my_model = form.save() # reference to my_model is often not needed at all, a simple form.save() is ok
# alternatively:
# my_model = form.save(commit=False) # create model, but don't save to database
# my.model.something = whatever # if I need to do something before saving it
# my.model.save()
else:
form = MyModelForm()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
Hope this clears up the usage of Django forms a bit.
Just one more note - it is perfectly ok to define form Fields on a ModelForm. These will not be used in form.save() but can still be access with form.cleaned_data just as in a regular Form.
Have you tried working with ModelForms before? As I understand, you're looking to create a form based on the model you created right?
Lets say your model is called Temp. You can create a form that correlates with this model (and your question) like this:
forms.py
from django.forms import ModelForm
class TempForm(ModelForm):
class Meta:
model = Temp
The ModelForm will automatically map the selections/choices from your model to a form version.
If you plan on using this in a template later, doing something like this will automatically create a drop-down menu with choices:
<form>
<label for="id_size">Size</label>
{{ form.size }}
</form>
Hope that answers your question!
Simply use CharField in your modelform as below:
SIZES_CHOICES = (
('size1', 'M'),
('size2', 'L'),
)
size = models.CharField(max_length=100, choices=SIZES_CHOICES, default=size1)
in the above code, size1 is the value which will be going to store in your database as name 'size1' and in the drop-down menu, there will be an option is 'M' of right side.you can mentioned any name to these options.