Django checkout model - django

What is the best way to create a checkout system with Django that keeps track of the checkout / checkin history?
My models for inventory/models.py
from django.db import models
class Groups(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
class Inventory(models.Model):
name = models.CharField(max_length=200)
serial = models.CharField(max_length=200)
barcode = models.CharField(max_length=200)
active = models.BooleanField(verbose_name="Active (can be checked out if not out for repair)",blank=True,default=True)
repair = models.BooleanField(verbose_name="Out for repair?",blank=True)
group = models.ForeignKey(Groups)
def __unicode__(self):
return self.name
I am thinking I will need another model that will store the checkout / in information? I am guessing I will need to only obtain the last one so that I know if it is checked in or out? I want to keep a history of the items so that I can create a report with it.
How would I go about making it so I have a history of the items and if the items can be checked in or out?

Yes, it isn't totally clear from your question what a checkout/checkin is, but my guess is you want something like
class Checkout(models.Model)
item = models.ForeignKey(Inventory)
user = models.ForeignKey(User)
checked_out = models.DateTimeField()
checked_in = models.DateTimeField(null=True)
...
You would then create one of these objects each time an item was checked out, and then update it to set the checkin date when it was checked back in.
To find the current checkout (or determine if something is not checked out) you could do a query like:
try:
checkout = Checkout.objects.get(item=my_item, checked_in=None)
except Checkout.DoesNotExist:
#item isn't checked out
checkout = None

Related

Django: Run a function if certain condition is met

I have a Word model, where a user can add words and various fields, like this (shortened version):
class Word(models.Model):
target_word = models.CharField()
source_word = models.CharField()
add_to_review = models.BooleanField(default=True)
example_sentence = models.CharField()
image = models.ImageField(upload_to='images/',blank=True)
audio = models.FileField(upload_to='audio/',blank=True)
I also have a Flashcard model where a user can add and study flashcards. Here I show only the relevant code:
class FlashcardManager(models.Manager):
def create_flashcard(self, user, question, answer, deck_name):
try:
deck = Deck.objects.get(owner=user, name=deck_name)
except ObjectDoesNotExist:
deck = Deck(owner=user, name=deck_name)
deck.save()
self.create(owner=user, question=question, answer=answer,
deck=deck)
return deck
class Flashcard(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
deck = models.ForeignKey(Deck, on_delete=models.CASCADE)
question = models.TextField()
answer = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
last_shown_at = models.DateTimeField(auto_now_add=True)
next_due_date = models.DateTimeField(default=timezone.now)
difficulty = models.FloatField(default=2.5)
consec_correct_answers = models.IntegerField(default=0)
objects = FlashcardManager()
def __str__(self):
return self.question
When a user creates a new word, I want to give them the option of automatically creating a flashcard using the info provided. In other words, question = target_word, answer = source_word, and the deck name can either be some default value, or I can add a field to the Word model. Is there a way I can do this by using the add_to_review field of the Word model and the create_flashcard method of the FlashcardManager model? I've tried adding a function to my Word model that runs if add_to_review is true. I don't get any errors, but nothing happens.
I know one option would be to just combine the two models... but I do have my own reasons for keeping them seperate. I might still do that, but I was just wondering if what I am trying to do is possible / feasible? I'm not really sure what exactly to google, so haven't been able to find any info on this. So any advice would be great, thanks!
Not sure if this is the best way, but it worked. Initially I had problems with the signal not being called, but this got fixed when I moved it to my models.py file instead of having it separate in a signals.py file.
#receiver(post_save, sender=Word)
def flash_from_word(sender, created, instance, **kwargs):
if created:
flash_wanted = Word.objects.filter(add_to_review=True)
instance._meta.model.objects.all()
target_word = instance.target_word
source_word = instance.source_word
deck_name = instance.deck_name
user = instance.user
if flash_wanted:
flash = Flashcard.objects.create(owner=user, question=target_word,answer=source_word,deck=Deck.objects.get(name=deck_name,owner=user))
post_save.connect(flash_from_word, sender=Word)

How would you model this in Django?

I want to upload a list of companies to my web app and then run some long background scripts on each company (ie. Webscraping). Each upload will be essentially be a batch task.
I suspect I will probably need to queue these batch processes with something like Redis or Celery, though I am not sure because the batch should start immediately after being being submitted.
I am mainly having trouble figuring out how to create my Models for this logic. So any help there would be greatly appreciated. Right now I've set up a Company model and a Batch model. I'm unsure on how to link these models together appropriately so I can sum up the number of employees from each company in a batch.
Please reference these pictures for visual details.
class Company(models.Model):
domain_name = models.CharField(max_length=100, verbose_name="Domain Name")
company_name = models.CharField(max_length=100, verbose_name="Company Name")
num_employees = models.IntegerField(default=0, verbose_name="# of Employees")
batch = models.ForeignKey('Batch', on_delete=models.CASCADE)
def __str__(self):
return f"Company: {self.company_name}\nEmployees: {self.num_employees}"
class Batch(models.Model):
batch_name = models.CharField(max_length=100, verbose_name="Batch Name")
batch_owner = models.CharField(max_length=100, verbose_name="Batch Owner")
create_date = models.DateTimeField('Date Created', auto_now=True)
# processing = models.BooleanField(verbose_name="Processing Status", default=False)
#property
def total_companies(self):
"""Gets imorted companies sum based on batch"""
pass
#property
def total_employees(self):
"""Gets sum of employees based on batch"""
pass
If there are going to be multiple batch instances for a single company, then a foreign key on the batch model to the company model should work.
class Company(models.Model):
some_fields = ....
class Batch(models.Model):
some_fields = ....
company = models.ForeignKey(Company, on_delete=models.PROTECT)
It looks like you already have a field in the Batch image for a company.
Looks like I figured out the models shortly after, I guess I used stackoverflow as my "rubberduck".
So if anyone runs into a similar issue, the model solution is in my question and in the selected answer.
On top of that, I was also able to map out a mock up of how the form view should work. I used some dummy data in a post_dict variable to imitate form data. And of course the request.method == 'GET' Should be 'POST' But for now I want this to process every time I load the respective URL as I haven't completed the form yet.
from itertools import islice
def create_batch_view(request):
if request.method == 'GET':
post_dict = {'batch_name': 'Some batch name',
'batch_owner': 'Developer',
'batch_items': ['company 1', 'company 2', 'company 3'],
}
batch_model = Batch(batch_name=post_dict['batch_name'],
batch_owner=post_dict['batch_owner'])
batch_model.save()
batch_size = 100
objs = (Company(batch=batch_model, company_name='Test %s' % i) for i in post_dict['batch_items'])
while True:
batch = list(islice(objs, batch_size))
if not batch:
break
Company.objects.bulk_create(batch, batch_size)
return redirect('index')
context = {
'form': BatchForm()
}
return render(request, 'createbatchform.html', context)
Hopefully this helps someone else. Now I just need to figure out the simplest way to run scripts on the batches and report back to the view when its done processing. Should I use a queue manager for this? For example. When a new batch is made, all the companies get added to the database like the example above and also a function is added to a queue manager. That function could look something like this:
def batch_process():
# Get batch
# Get Companies related to batch.
# Loop through companies.
# Scrape Data for company and save it back to database.
# Finish and set Batch.processing = False to signal the process is finished.

django cms plugin that display model with specific value checked

I made a model that displays articles and when you create an article you have the possibility to choose if this article will be a featured one.
So this is basically what I have in my Article model :
class Article(ModelMeta, TranslatableModel):
taints_cache = True
"""
Press article element,
"""
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
date_realization = models.DateField(_('Realised in'),
default=timezone.now)
image = FilerImageField(verbose_name=_('Featured image'), blank=True,
null=True,
on_delete=models.SET_NULL,
related_name='image_press_article',
help_text=_('Set if the article will be featured'))
sources = models.ManyToManyField(ArticleSource, verbose_name=_('Source'),
blank=False, null=True, related_name='sources_press_article')
regions = models.ManyToManyField(Country, verbose_name=_('Country of the article'),
blank=True, null=True,
related_name='regions_press_article')
global_regions = models.BooleanField('Global', default=True)
featureArticle = models.BooleanField(_('Feature'), help_text=_('Feature this article'), default=False)
Then, I created a plugin that displays the featured articles.
But the thing is, in the django plugin admin I let the user the possibility to choose which article he wants to display (with a maximum of 3).
But in this choosing list, all my articles are listed.
What I want to, is to list only the articles that are checked as "featured", in my plugin admin. Instead of having all the articles.
Here what I have with my cms_plugin's model :
class FeaturedArticlePlugin(CMSPlugin):
selected_article = SortedManyToManyField(Article, blank=True, verbose_name=_('Selected articles'),
help_text=_('Select the featured articles to display'))
def __str__(self):
return u'%s Selected articles' % self.selected_article.all()
def copy_relations(self, oldinstance):
self.selected_article = oldinstance.selected_article.all()
And in my cms_plugins.py :
class PressPlugin(CMSPluginBase):
module = 'Press'
class PressFeaturedArticlePlugin(PressPlugin):
module = _('Press')
name = _('Press feature')
model = FeaturedArticlePlugin
render_template = 'djangocms_press/plugins/feature_article.html'
number_article = 3
def render(self, context, instance, placeholder):
"""
Get a list of selected_articles
"""
selected_article = instance.selected_article.all()
number_selected_article = selected_article.count()
feature_article_list = list(selected_article[:self.number_article])
context['instance'] = instance
context['feature_article_list'] = feature_article_list
return context
plugin_pool.register_plugin(PressFeaturedArticlePlugin)
So, I am sure it's nothing complicated but I can't point this out.
Anyone has a clue ?
EDIT
From what I understand, the only thing that concern the display of all articles is this line :
selected_article = SortedManyToManyField(Article, blank=True, verbose_name=_('Selected articles'),
help_text=_('Select the featured articles to display'))
So what I am suppose to do is to filter this selected_article with the featureArticle=True. But how to do it ?
I am not quite sure if I am missing something, but, couldn't you just apply a filter here?
selected_article = instance.selected_article.all().filter(featureArticle=true)
number_selected_article = selected_article.count()
Or is the problem with the lines after?
feature_article_list = list(selected_article[:self.number_article])
If your problem is selecting the extra articles, maybe you need to order them by date and select only the necessary?
feature_article_list = list(Articles.all().order_by('-created')[:self.number_article - number_selected_article]
Which will only select the extra necessaries?
Edit: Your situation kind of reminds me of a problem I once had. So I'll refer you to the same page that helped me in the past just in case you'd manage to figure it out.
Restrict django admin change permissions
Edit 2 : "I created a plugin that displays the featured articles. But the thing is, in the django plugin admin I let the user the possibility to choose which article he wants to display (with a maximum of 3). But in this choosing list, all my articles are listed."
Isn't it ok if all the articles are displayed there? How can you choose among them if they are not all displayed?

Django bulk edit form

In my project I have a many-to-one relation with one Serie having up to 20 samples. I'm trying to implement a system where a user uploads a (csv)file and is then sent to a page where they can fill in any missing data. I haven't found a way to implement this and was looking for some help. The idea is that I want a table with each row having 4 fields, which are linked to the sample in question and the table will have as many rows as there were samples in the (csv)file. Furthermore, if data is already present for one of the fields, I want it to prefill the field in question. In the end, the updated data is committed by pressing a single save button at the bottom so it's supposed to be one big form.
I've added the models below. The attributes which I want to update in the form are index, pool and remarks, which may be present in the csv file already but often they aren't.
Can anyone give me any tips on how to implement this or hint at methods which are best for implementing something like this?
Models
class Sample(models.Model):
name = models.CharField(max_length=20)
pool = models.ForeignKey(Pool, blank=True, null=True)
serie = models.ForeignKey(Serie, blank=True, null = True)
index = models.ForeignKey(Index, blank=True, null=True)
remarks = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.name
class Serie(models.Model):
a_type = models.ForeignKey(Atype)
name = models.IntegerField()
def __str__(self):
return str(self.a_type)+'-'+str(self.name)
Views
def serie_edit(request,serie_id):
try:
serie = Serie.objects.get(pk=serie_id)
except Serie.DoesNotExist:
raise Http404
index_list = Index.objects.all()
sample_list = Sample.objects.filter(serie__id = serie_id)
return render(request, 'samples/serie_edit.html', {'serie':serie, 'sample_list':sample_list, 'index_list':index_list})

How to build SQL query with two left joins using django ORM

I need to build an MySQL query and I want to try with django ORM first and then use raw as last resort.
I found documentation on single JOIN or JOINs between two tables but there is no examples or at least a simple (beginner wise) explanation of JOINs between three tables
Content of models.py is
from django.db import models
# Create your models here.
class Threads(models.Model):
name = models.CharField(max_length=100)
author = models.CharField(max_length=100)
date = models.DateTimeField("date published")
slug = models.SlugField()
def __unicode__(self):
return self.name
class Posts(models.Model):
name = models.CharField(max_length=100)
text = models.TextField()
author = models.CharField(max_length=100)
date = models.DateTimeField("date published")
slug = models.SlugField()
def __unicode__(self):
return self.name
class Relations(models.Model):
thread = models.ForeignKey(Threads, related_name = "%(app_label)s_%(class)s_related")
post = models.ForeignKey(Posts, related_name = "%(app_label)s_%(class)s_related")
and this is SQL query in raw that I am trying to build
SELECT forum_threads.id AS t_id, forum_threads.name AS t_name, forum_threads.slug AS t_slug, forum_posts.*
FROM forum_threads
LEFT JOIN forum_relations ON forum_threads.id=forum_relations.thread_id
LEFT JOIN forum_posts ON forum_relations.post_id=forum_posts.id
WHERE forum_threads.slug="<slug_name>"
GROUP BY forum_threads.id
"forum" is my app name
Now I don't know if I need to tweak/change my Models and if, how. Note that I can change my models no important data whatsoever.
EDIT
Thank you for all your answers!
Ok I played a bit with various examples until i managed to produce someting. I got it like this:
thread = Threads.objects.filter(slug = slug)
posts = Posts.objects.filter(forum_relations_related__thread = thread[0].id)
first query is to retrieve id of thread from slug and second one returns all post related to thread on that thread id.
I'll try and play around with a M2M part since I have at least one working example.
Why not just use a M2M relation, you can use through if need be.
You could then get a thread by slug
thread = Threads.objects.get(slug=slug_name)
then you can access the posts related to a thread via
thread.posts_set.all()